@kroonen-ai/librebot-widget 1.1.1 → 1.2.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.
@@ -482,6 +482,7 @@ class LibreBotWidget {
482
482
  this.isOpen = false;
483
483
  this.messages = [];
484
484
  this.isLoading = false;
485
+ this.sessionId = null;
485
486
  this.defaultConfig = {
486
487
  apiUrl: 'https://librebot.io/api',
487
488
  position: 'bottom-right',
@@ -554,6 +555,8 @@ class LibreBotWidget {
554
555
  return provided;
555
556
  }
556
557
  init() {
558
+ // Load sessionId from localStorage for persistent memory
559
+ this.loadSession();
557
560
  // Inject styles
558
561
  this.injectStyles();
559
562
  // Create widget container
@@ -563,6 +566,29 @@ class LibreBotWidget {
563
566
  this.addMessage('assistant', this.config.welcomeMessage);
564
567
  }
565
568
  }
569
+ getSessionKey() {
570
+ return `librebot_session_${this.config.apiKey}`;
571
+ }
572
+ loadSession() {
573
+ try {
574
+ const stored = localStorage.getItem(this.getSessionKey());
575
+ if (stored) {
576
+ this.sessionId = stored;
577
+ }
578
+ }
579
+ catch {
580
+ // localStorage may not be available
581
+ }
582
+ }
583
+ saveSession(sessionId) {
584
+ try {
585
+ this.sessionId = sessionId;
586
+ localStorage.setItem(this.getSessionKey(), sessionId);
587
+ }
588
+ catch {
589
+ // localStorage may not be available
590
+ }
591
+ }
566
592
  injectStyles() {
567
593
  const styleId = 'librebot-styles';
568
594
  if (document.getElementById(styleId))
@@ -801,6 +827,7 @@ class LibreBotWidget {
801
827
  message,
802
828
  context: this.getConversationContext(),
803
829
  stream: true,
830
+ sessionId: this.sessionId,
804
831
  }),
805
832
  });
806
833
  if (!response.ok) {
@@ -840,6 +867,10 @@ class LibreBotWidget {
840
867
  messageEl.innerHTML = this.formatMessage(fullContent);
841
868
  this.scrollToBottom();
842
869
  }
870
+ // Save sessionId when received from server
871
+ if (parsed.sessionId) {
872
+ this.saveSession(parsed.sessionId);
873
+ }
843
874
  }
844
875
  catch {
845
876
  // Skip malformed JSON
@@ -869,13 +900,19 @@ class LibreBotWidget {
869
900
  body: JSON.stringify({
870
901
  message,
871
902
  context: this.getConversationContext(),
903
+ sessionId: this.sessionId,
872
904
  }),
873
905
  });
874
906
  if (!response.ok) {
875
907
  const error = await response.json().catch(() => ({ error: 'Request failed' }));
876
908
  return { response: '', error: error.error || 'Request failed' };
877
909
  }
878
- return response.json();
910
+ const data = await response.json();
911
+ // Save sessionId when received from server
912
+ if (data.sessionId) {
913
+ this.saveSession(data.sessionId);
914
+ }
915
+ return data;
879
916
  }
880
917
  getConversationContext() {
881
918
  // Get last 10 messages for context
@@ -888,6 +925,23 @@ class LibreBotWidget {
888
925
  this.container?.remove();
889
926
  document.getElementById('librebot-styles')?.remove();
890
927
  }
928
+ clearSession() {
929
+ try {
930
+ this.sessionId = null;
931
+ this.messages = [];
932
+ localStorage.removeItem(this.getSessionKey());
933
+ if (this.messagesContainer) {
934
+ this.messagesContainer.innerHTML = '';
935
+ }
936
+ // Re-add welcome message
937
+ if (this.config.welcomeMessage) {
938
+ this.addMessage('assistant', this.config.welcomeMessage);
939
+ }
940
+ }
941
+ catch {
942
+ // localStorage may not be available
943
+ }
944
+ }
891
945
  }
892
946
 
893
947
  export { LibreBotWidget };
@@ -1 +1 @@
1
- {"version":3,"file":"librebot.esm.js","sources":["../src/styles.ts","../src/icons.ts","../src/widget.ts"],"sourcesContent":["export const getStyles = (primaryColor: string = '#14b8a6') => `\n .librebot-widget {\n --lb-primary: ${primaryColor};\n --lb-primary-hover: color-mix(in srgb, ${primaryColor} 85%, white);\n --lb-bg: #0f0f0f;\n --lb-bg-secondary: #1a1a1a;\n --lb-text: #ffffff;\n --lb-text-secondary: #9ca3af;\n --lb-border: #2a2a2a;\n font-family: 'Roboto Mono', -apple-system, BlinkMacSystemFont, 'Segoe UI', monospace;\n font-size: 14px;\n line-height: 1.5;\n }\n\n .librebot-widget.light {\n --lb-bg: #ffffff;\n --lb-bg-secondary: #f5f5f5;\n --lb-text: #1a1a1a;\n --lb-text-secondary: #666666;\n --lb-border: #e0e0e0;\n }\n\n .librebot-fab {\n position: fixed;\n bottom: 20px;\n right: 20px;\n width: 56px;\n height: 56px;\n border-radius: 50%;\n background: var(--lb-primary);\n border: none;\n cursor: pointer;\n box-shadow: 0 4px 12px rgba(0, 0, 0, 0.3);\n display: flex;\n align-items: center;\n justify-content: center;\n transition: transform 0.2s, box-shadow 0.2s;\n z-index: 999998;\n }\n\n .librebot-fab:hover {\n transform: scale(1.05);\n box-shadow: 0 6px 16px rgba(0, 0, 0, 0.4);\n }\n\n .librebot-fab svg {\n width: 24px;\n height: 24px;\n fill: white;\n }\n\n .librebot-fab.left {\n right: auto;\n left: 20px;\n }\n\n .librebot-modal {\n position: fixed;\n bottom: 90px;\n right: 20px;\n width: 380px;\n max-width: calc(100vw - 40px);\n height: 520px;\n max-height: calc(100vh - 120px);\n background: var(--lb-bg);\n border: 1px solid var(--lb-border);\n border-radius: 16px;\n box-shadow: 0 8px 32px rgba(0, 0, 0, 0.3);\n display: flex;\n flex-direction: column;\n overflow: hidden;\n z-index: 999999;\n opacity: 0;\n transform: translateY(20px) scale(0.95);\n transition: opacity 0.2s, transform 0.2s;\n pointer-events: none;\n }\n\n .librebot-modal.open {\n opacity: 1;\n transform: translateY(0) scale(1);\n pointer-events: auto;\n }\n\n .librebot-modal.left {\n right: auto;\n left: 20px;\n }\n\n .librebot-header {\n padding: 16px;\n border-bottom: 1px solid var(--lb-border);\n display: flex;\n align-items: center;\n justify-content: space-between;\n }\n\n .librebot-header-content {\n display: flex;\n align-items: center;\n gap: 12px;\n }\n\n .librebot-avatar {\n width: 40px;\n height: 40px;\n border-radius: 10px;\n background: var(--lb-primary);\n display: flex;\n align-items: center;\n justify-content: center;\n }\n\n .librebot-avatar svg {\n width: 24px;\n height: 24px;\n fill: white;\n }\n\n .librebot-title {\n font-weight: 600;\n color: var(--lb-text);\n margin: 0;\n font-size: 16px;\n }\n\n .librebot-subtitle {\n font-size: 12px;\n color: var(--lb-text-secondary);\n margin: 0;\n }\n\n .librebot-close {\n width: 32px;\n height: 32px;\n border-radius: 8px;\n border: none;\n background: transparent;\n cursor: pointer;\n display: flex;\n align-items: center;\n justify-content: center;\n color: var(--lb-text-secondary);\n transition: background 0.2s;\n }\n\n .librebot-close:hover {\n background: var(--lb-bg-secondary);\n }\n\n .librebot-messages {\n flex: 1;\n overflow-y: auto;\n padding: 16px;\n display: flex;\n flex-direction: column;\n gap: 12px;\n }\n\n .librebot-message {\n max-width: 85%;\n padding: 10px 14px;\n border-radius: 16px;\n word-wrap: break-word;\n }\n\n .librebot-message.user {\n align-self: flex-end;\n background: var(--lb-primary);\n color: white;\n border-bottom-right-radius: 4px;\n }\n\n .librebot-message.assistant {\n align-self: flex-start;\n background: var(--lb-bg-secondary);\n color: var(--lb-text);\n border-bottom-left-radius: 4px;\n }\n\n /* Inline code */\n .librebot-inline-code {\n background: rgba(0, 0, 0, 0.3);\n padding: 2px 6px;\n border-radius: 4px;\n font-family: 'Roboto Mono', 'Fira Code', 'Consolas', monospace;\n font-size: 12px;\n color: #f0f0f0;\n }\n\n .librebot-widget.light .librebot-inline-code {\n background: rgba(0, 0, 0, 0.08);\n color: #1a1a1a;\n }\n\n /* Code blocks */\n .librebot-code-block {\n background: #0d1117;\n padding: 12px 14px;\n border-radius: 8px;\n overflow-x: auto;\n margin: 10px 0;\n border: 1px solid rgba(255, 255, 255, 0.1);\n position: relative;\n }\n\n .librebot-widget.light .librebot-code-block {\n background: #f6f8fa;\n border-color: rgba(0, 0, 0, 0.1);\n }\n\n .librebot-code-block code {\n font-family: 'Roboto Mono', 'Fira Code', 'Consolas', monospace;\n font-size: 12px;\n line-height: 1.5;\n color: #e6edf3;\n background: none;\n padding: 0;\n white-space: pre;\n display: block;\n }\n\n .librebot-widget.light .librebot-code-block code {\n color: #24292f;\n }\n\n .librebot-code-block[data-language]::before {\n content: attr(data-language);\n position: absolute;\n top: 6px;\n right: 10px;\n font-size: 10px;\n color: rgba(255, 255, 255, 0.4);\n text-transform: uppercase;\n font-family: 'Roboto Mono', monospace;\n }\n\n .librebot-widget.light .librebot-code-block[data-language]::before {\n color: rgba(0, 0, 0, 0.3);\n }\n\n /* Headers */\n .librebot-h2 {\n font-size: 16px;\n font-weight: 600;\n margin: 12px 0 8px 0;\n color: var(--lb-text);\n }\n\n .librebot-h3 {\n font-size: 14px;\n font-weight: 600;\n margin: 10px 0 6px 0;\n color: var(--lb-text);\n }\n\n .librebot-h4 {\n font-size: 13px;\n font-weight: 600;\n margin: 8px 0 4px 0;\n color: var(--lb-text);\n }\n\n /* Lists */\n .librebot-ul, .librebot-ol {\n margin: 8px 0;\n padding-left: 20px;\n }\n\n .librebot-ul {\n list-style-type: disc;\n }\n\n .librebot-ol {\n list-style-type: decimal;\n }\n\n .librebot-li, .librebot-li-ordered {\n margin: 4px 0;\n padding-left: 4px;\n line-height: 1.5;\n }\n\n /* Links */\n .librebot-link {\n color: var(--lb-primary);\n text-decoration: none;\n border-bottom: 1px solid transparent;\n transition: border-color 0.2s;\n }\n\n .librebot-link:hover {\n border-bottom-color: var(--lb-primary);\n }\n\n /* Blockquotes */\n .librebot-blockquote {\n border-left: 3px solid var(--lb-primary);\n margin: 8px 0;\n padding: 4px 12px;\n color: var(--lb-text-secondary);\n font-style: italic;\n background: rgba(0, 0, 0, 0.1);\n border-radius: 0 6px 6px 0;\n }\n\n .librebot-widget.light .librebot-blockquote {\n background: rgba(0, 0, 0, 0.04);\n }\n\n /* Horizontal rule */\n .librebot-hr {\n border: none;\n border-top: 1px solid var(--lb-border);\n margin: 12px 0;\n }\n\n /* Strong and emphasis */\n .librebot-message strong {\n font-weight: 600;\n }\n\n .librebot-message em {\n font-style: italic;\n }\n\n /* Legacy support for old code elements */\n .librebot-message code:not(.librebot-inline-code) {\n background: rgba(0, 0, 0, 0.2);\n padding: 2px 6px;\n border-radius: 4px;\n font-family: monospace;\n font-size: 13px;\n }\n\n .librebot-message pre:not(.librebot-code-block) {\n background: rgba(0, 0, 0, 0.3);\n padding: 10px;\n border-radius: 8px;\n overflow-x: auto;\n margin: 8px 0;\n }\n\n .librebot-message pre:not(.librebot-code-block) code {\n background: none;\n padding: 0;\n }\n\n .librebot-typing {\n display: flex;\n gap: 4px;\n padding: 12px 16px;\n align-self: flex-start;\n background: var(--lb-bg-secondary);\n border-radius: 16px;\n border-bottom-left-radius: 4px;\n }\n\n .librebot-typing span {\n width: 8px;\n height: 8px;\n background: var(--lb-text-secondary);\n border-radius: 50%;\n animation: librebot-bounce 1.4s infinite ease-in-out;\n }\n\n .librebot-typing span:nth-child(1) { animation-delay: 0s; }\n .librebot-typing span:nth-child(2) { animation-delay: 0.2s; }\n .librebot-typing span:nth-child(3) { animation-delay: 0.4s; }\n\n @keyframes librebot-bounce {\n 0%, 80%, 100% { transform: scale(0.8); opacity: 0.5; }\n 40% { transform: scale(1); opacity: 1; }\n }\n\n .librebot-input-area {\n padding: 12px 16px;\n border-top: 1px solid var(--lb-border);\n display: flex;\n gap: 8px;\n }\n\n .librebot-input {\n flex: 1;\n padding: 10px 14px;\n border: 1px solid var(--lb-border);\n border-radius: 24px;\n background: var(--lb-bg-secondary);\n color: var(--lb-text);\n font-size: 14px;\n outline: none;\n transition: border-color 0.2s;\n }\n\n .librebot-input:focus {\n border-color: var(--lb-primary);\n }\n\n .librebot-input::placeholder {\n color: var(--lb-text-secondary);\n }\n\n .librebot-send {\n width: 40px;\n height: 40px;\n border-radius: 50%;\n border: none;\n background: var(--lb-primary);\n cursor: pointer;\n display: flex;\n align-items: center;\n justify-content: center;\n transition: background 0.2s;\n }\n\n .librebot-send:hover {\n background: var(--lb-primary-hover);\n }\n\n .librebot-send:disabled {\n opacity: 0.5;\n cursor: not-allowed;\n }\n\n .librebot-send svg {\n width: 18px;\n height: 18px;\n fill: white;\n }\n\n .librebot-welcome {\n text-align: center;\n padding: 20px;\n color: var(--lb-text-secondary);\n }\n\n .librebot-welcome-icon {\n width: 48px;\n height: 48px;\n margin: 0 auto 12px;\n background: var(--lb-primary);\n border-radius: 12px;\n display: flex;\n align-items: center;\n justify-content: center;\n }\n\n .librebot-welcome-icon svg {\n width: 28px;\n height: 28px;\n fill: white;\n }\n\n .librebot-powered {\n text-align: center;\n padding: 8px;\n font-size: 11px;\n color: var(--lb-text-secondary);\n border-top: 1px solid var(--lb-border);\n }\n\n .librebot-powered a {\n color: var(--lb-primary);\n text-decoration: none;\n }\n\n .librebot-powered a:hover {\n text-decoration: underline;\n }\n`;\n","export const chatIcon = `<svg viewBox=\"0 0 24 24\" fill=\"none\" stroke=\"currentColor\" stroke-width=\"2\" stroke-linecap=\"round\" stroke-linejoin=\"round\"><path d=\"M21 15a2 2 0 0 1-2 2H7l-4 4V5a2 2 0 0 1 2-2h14a2 2 0 0 1 2 2z\"></path></svg>`;\n\nexport const closeIcon = `<svg viewBox=\"0 0 24 24\" fill=\"none\" stroke=\"currentColor\" stroke-width=\"2\" stroke-linecap=\"round\" stroke-linejoin=\"round\"><line x1=\"18\" y1=\"6\" x2=\"6\" y2=\"18\"></line><line x1=\"6\" y1=\"6\" x2=\"18\" y2=\"18\"></line></svg>`;\n\nexport const sendIcon = `<svg viewBox=\"0 0 24 24\" fill=\"none\" stroke=\"currentColor\" stroke-width=\"2\" stroke-linecap=\"round\" stroke-linejoin=\"round\"><line x1=\"22\" y1=\"2\" x2=\"11\" y2=\"13\"></line><polygon points=\"22 2 15 22 11 13 2 9 22 2\"></polygon></svg>`;\n\nexport const botIcon = `<svg viewBox=\"0 0 24 24\" fill=\"currentColor\"><path d=\"M12 2C6.48 2 2 6.48 2 12s4.48 10 10 10 10-4.48 10-10S17.52 2 12 2zm-2 15l-5-5 1.41-1.41L10 14.17l7.59-7.59L19 8l-9 9z\"/></svg>`;\n","import { LibreBotConfig, Message, ChatResponse } from './types';\nimport { getStyles } from './styles';\nimport { chatIcon, closeIcon, sendIcon } from './icons';\n\nexport class LibreBotWidget {\n private config!: Required<LibreBotConfig>;\n private container: HTMLDivElement | null = null;\n private modal: HTMLDivElement | null = null;\n private messagesContainer: HTMLDivElement | null = null;\n private input: HTMLInputElement | null = null;\n private isOpen = false;\n private messages: Message[] = [];\n private isLoading = false;\n\n private defaultConfig: Omit<Required<LibreBotConfig>, 'apiKey'> = {\n apiUrl: 'https://librebot.io/api',\n position: 'bottom-right',\n theme: 'dark',\n primaryColor: '#14b8a6',\n title: 'Libre Bot',\n subtitle: 'AI Documentation Assistant',\n placeholder: 'Ask a question...',\n welcomeMessage: 'Hi! I can help you find answers in the documentation. What would you like to know?',\n streaming: true,\n whiteLabel: false,\n autoLoadConfig: true,\n };\n\n constructor(config: LibreBotConfig) {\n if (!config.apiKey) {\n console.error('LibreBot: API key is required');\n return;\n }\n\n this.config = { ...this.defaultConfig, ...config } as Required<LibreBotConfig>;\n\n // Auto-load config from server if enabled and no custom settings provided\n if (this.config.autoLoadConfig) {\n this.loadRemoteConfig().then(() => this.init());\n } else {\n this.init();\n }\n }\n\n private async loadRemoteConfig(): Promise<void> {\n try {\n const response = await fetch(`${this.config.apiUrl}/widget-config?key=${this.config.apiKey}`);\n if (response.ok) {\n const remoteConfig = await response.json();\n // Merge remote config with local config (local overrides remote)\n this.config = {\n ...this.defaultConfig,\n ...remoteConfig,\n ...this.getProvidedConfig(),\n apiKey: this.config.apiKey,\n apiUrl: this.config.apiUrl,\n autoLoadConfig: this.config.autoLoadConfig,\n } as Required<LibreBotConfig>;\n }\n } catch (error) {\n console.warn('LibreBot: Could not load remote config, using defaults', error);\n }\n }\n\n private getProvidedConfig(): Partial<LibreBotConfig> {\n // Return only the config options that were explicitly provided (not default values)\n const provided: Partial<LibreBotConfig> = {};\n const userConfig = this.config;\n const defaults = this.defaultConfig;\n\n if (userConfig.position !== defaults.position) provided.position = userConfig.position;\n if (userConfig.theme !== defaults.theme) provided.theme = userConfig.theme;\n if (userConfig.primaryColor !== defaults.primaryColor) provided.primaryColor = userConfig.primaryColor;\n if (userConfig.title !== defaults.title) provided.title = userConfig.title;\n if (userConfig.subtitle !== defaults.subtitle) provided.subtitle = userConfig.subtitle;\n if (userConfig.placeholder !== defaults.placeholder) provided.placeholder = userConfig.placeholder;\n if (userConfig.welcomeMessage !== defaults.welcomeMessage) provided.welcomeMessage = userConfig.welcomeMessage;\n if (userConfig.streaming !== defaults.streaming) provided.streaming = userConfig.streaming;\n if (userConfig.whiteLabel !== defaults.whiteLabel) provided.whiteLabel = userConfig.whiteLabel;\n\n return provided;\n }\n\n private init(): void {\n // Inject styles\n this.injectStyles();\n\n // Create widget container\n this.createWidget();\n\n // Add welcome message\n if (this.config.welcomeMessage) {\n this.addMessage('assistant', this.config.welcomeMessage);\n }\n }\n\n private injectStyles(): void {\n const styleId = 'librebot-styles';\n if (document.getElementById(styleId)) return;\n\n const style = document.createElement('style');\n style.id = styleId;\n style.textContent = getStyles(this.config.primaryColor);\n document.head.appendChild(style);\n }\n\n private createWidget(): void {\n // Create container\n this.container = document.createElement('div');\n this.container.className = `librebot-widget ${this.config.theme === 'light' ? 'light' : ''}`;\n\n // Create FAB button\n const fab = document.createElement('button');\n fab.className = `librebot-fab ${this.config.position === 'bottom-left' ? 'left' : ''}`;\n fab.innerHTML = chatIcon;\n fab.onclick = () => this.toggle();\n\n // Create modal\n this.modal = document.createElement('div');\n this.modal.className = `librebot-modal ${this.config.position === 'bottom-left' ? 'left' : ''}`;\n this.modal.innerHTML = this.getModalHTML();\n\n // Add to container\n this.container.appendChild(fab);\n this.container.appendChild(this.modal);\n document.body.appendChild(this.container);\n\n // Get references\n this.messagesContainer = this.modal.querySelector('.librebot-messages');\n this.input = this.modal.querySelector('.librebot-input');\n\n // Add event listeners\n const closeBtn = this.modal.querySelector('.librebot-close');\n closeBtn?.addEventListener('click', () => this.close());\n\n const sendBtn = this.modal.querySelector('.librebot-send');\n sendBtn?.addEventListener('click', () => this.sendMessage());\n\n this.input?.addEventListener('keypress', (e) => {\n if (e.key === 'Enter' && !e.shiftKey) {\n e.preventDefault();\n this.sendMessage();\n }\n });\n\n // Auto theme detection\n if (this.config.theme === 'auto') {\n const mediaQuery = window.matchMedia('(prefers-color-scheme: light)');\n this.updateTheme(mediaQuery.matches);\n mediaQuery.addEventListener('change', (e) => this.updateTheme(e.matches));\n }\n }\n\n private getModalHTML(): string {\n const poweredByHtml = this.config.whiteLabel\n ? ''\n : `<div class=\"librebot-powered\">\n Powered by <a href=\"https://librebot.io\" target=\"_blank\">Libre Bot</a>\n </div>`;\n\n return `\n <div class=\"librebot-header\">\n <div class=\"librebot-header-content\">\n <div class=\"librebot-avatar\">${chatIcon}</div>\n <div>\n <h3 class=\"librebot-title\">${this.config.title}</h3>\n <p class=\"librebot-subtitle\">${this.config.subtitle}</p>\n </div>\n </div>\n <button class=\"librebot-close\">${closeIcon}</button>\n </div>\n <div class=\"librebot-messages\"></div>\n <div class=\"librebot-input-area\">\n <input type=\"text\" class=\"librebot-input\" placeholder=\"${this.config.placeholder}\" />\n <button class=\"librebot-send\">${sendIcon}</button>\n </div>\n ${poweredByHtml}\n `;\n }\n\n private updateTheme(isLight: boolean): void {\n if (isLight) {\n this.container?.classList.add('light');\n } else {\n this.container?.classList.remove('light');\n }\n }\n\n public toggle(): void {\n this.isOpen ? this.close() : this.open();\n }\n\n public open(): void {\n this.isOpen = true;\n this.modal?.classList.add('open');\n this.input?.focus();\n }\n\n public close(): void {\n this.isOpen = false;\n this.modal?.classList.remove('open');\n }\n\n private addMessage(role: 'user' | 'assistant', content: string): void {\n const message: Message = {\n id: `msg-${Date.now()}`,\n role,\n content,\n timestamp: new Date(),\n };\n\n this.messages.push(message);\n this.renderMessage(message);\n }\n\n private renderMessage(message: Message): void {\n if (!this.messagesContainer) return;\n\n const el = document.createElement('div');\n el.className = `librebot-message ${message.role}`;\n el.innerHTML = this.formatMessage(message.content);\n\n this.messagesContainer.appendChild(el);\n this.scrollToBottom();\n }\n\n private formatMessage(content: string): string {\n // Escape HTML to prevent XSS\n const escapeHtml = (text: string): string => {\n return text\n .replace(/&/g, '&amp;')\n .replace(/</g, '&lt;')\n .replace(/>/g, '&gt;')\n .replace(/\"/g, '&quot;')\n .replace(/'/g, '&#039;');\n };\n\n // First, extract code blocks to protect them from other formatting\n // Regex handles optional space/newline after ``` and optional language identifier\n const codeBlocks: string[] = [];\n let processed = content.replace(/```\\s*(\\w*)\\s*\\n?([\\s\\S]*?)```/g, (_, lang, code) => {\n const escaped = escapeHtml(code.trim());\n const langClass = lang ? ` data-language=\"${escapeHtml(lang)}\"` : '';\n codeBlocks.push(`<pre class=\"librebot-code-block\"${langClass}><code>${escaped}</code></pre>`);\n return `%%CODEBLOCK${codeBlocks.length - 1}%%`;\n });\n\n // Extract inline code\n const inlineCodes: string[] = [];\n processed = processed.replace(/`([^`]+)`/g, (_, code) => {\n inlineCodes.push(`<code class=\"librebot-inline-code\">${escapeHtml(code)}</code>`);\n return `%%INLINECODE${inlineCodes.length - 1}%%`;\n });\n\n // Now escape remaining HTML\n processed = escapeHtml(processed);\n\n // Headers (## and ###)\n processed = processed.replace(/^### (.+)$/gm, '<h4 class=\"librebot-h4\">$1</h4>');\n processed = processed.replace(/^## (.+)$/gm, '<h3 class=\"librebot-h3\">$1</h3>');\n processed = processed.replace(/^# (.+)$/gm, '<h2 class=\"librebot-h2\">$1</h2>');\n\n // Bold and italic\n processed = processed.replace(/\\*\\*\\*([^*]+)\\*\\*\\*/g, '<strong><em>$1</em></strong>');\n processed = processed.replace(/\\*\\*([^*]+)\\*\\*/g, '<strong>$1</strong>');\n processed = processed.replace(/\\*([^*]+)\\*/g, '<em>$1</em>');\n processed = processed.replace(/_([^_]+)_/g, '<em>$1</em>');\n\n // Links [text](url)\n processed = processed.replace(/\\[([^\\]]+)\\]\\(([^)]+)\\)/g, '<a href=\"$2\" target=\"_blank\" rel=\"noopener noreferrer\" class=\"librebot-link\">$1</a>');\n\n // Unordered lists\n processed = processed.replace(/^[\\*\\-] (.+)$/gm, '<li class=\"librebot-li\">$1</li>');\n processed = processed.replace(/(<li class=\"librebot-li\">.*<\\/li>\\n?)+/g, (match) => {\n return `<ul class=\"librebot-ul\">${match}</ul>`;\n });\n\n // Ordered lists\n processed = processed.replace(/^\\d+\\. (.+)$/gm, '<li class=\"librebot-li-ordered\">$1</li>');\n processed = processed.replace(/(<li class=\"librebot-li-ordered\">.*<\\/li>\\n?)+/g, (match) => {\n return `<ol class=\"librebot-ol\">${match}</ol>`;\n });\n\n // Horizontal rule\n processed = processed.replace(/^---$/gm, '<hr class=\"librebot-hr\">');\n\n // Blockquotes\n processed = processed.replace(/^&gt; (.+)$/gm, '<blockquote class=\"librebot-blockquote\">$1</blockquote>');\n\n // Convert newlines to <br> (but not inside lists/blockquotes)\n processed = processed.replace(/\\n/g, '<br>');\n\n // Clean up extra <br> after block elements\n processed = processed.replace(/<\\/(pre|ul|ol|blockquote|h[2-4])><br>/g, '</$1>');\n processed = processed.replace(/<br><(pre|ul|ol|blockquote|h[2-4])/g, '<$1');\n\n // Restore code blocks\n codeBlocks.forEach((block, i) => {\n processed = processed.replace(`%%CODEBLOCK${i}%%`, block);\n });\n\n // Restore inline code\n inlineCodes.forEach((code, i) => {\n processed = processed.replace(`%%INLINECODE${i}%%`, code);\n });\n\n return processed;\n }\n\n private showTyping(): HTMLDivElement {\n const typing = document.createElement('div');\n typing.className = 'librebot-typing';\n typing.innerHTML = '<span></span><span></span><span></span>';\n this.messagesContainer?.appendChild(typing);\n this.scrollToBottom();\n return typing;\n }\n\n private scrollToBottom(): void {\n if (this.messagesContainer) {\n this.messagesContainer.scrollTop = this.messagesContainer.scrollHeight;\n }\n }\n\n private async sendMessage(): Promise<void> {\n if (!this.input || this.isLoading) return;\n\n const content = this.input.value.trim();\n if (!content) return;\n\n // Add user message\n this.addMessage('user', content);\n this.input.value = '';\n\n // Show typing indicator\n this.isLoading = true;\n const typing = this.showTyping();\n\n try {\n if (this.config.streaming) {\n await this.callStreamingAPI(content, typing);\n } else {\n const response = await this.callAPI(content);\n typing.remove();\n\n if (response.error) {\n this.addMessage('assistant', `Sorry, I encountered an error: ${response.error}`);\n } else {\n this.addMessage('assistant', response.response);\n }\n }\n } catch (error) {\n typing.remove();\n this.addMessage('assistant', 'Sorry, I had trouble connecting. Please try again.');\n console.error('LibreBot error:', error);\n } finally {\n this.isLoading = false;\n }\n }\n\n private async callStreamingAPI(message: string, typing: HTMLDivElement): Promise<void> {\n const response = await fetch(`${this.config.apiUrl}/chat`, {\n method: 'POST',\n headers: {\n 'Content-Type': 'application/json',\n Authorization: `Bearer ${this.config.apiKey}`,\n },\n body: JSON.stringify({\n message,\n context: this.getConversationContext(),\n stream: true,\n }),\n });\n\n if (!response.ok) {\n typing.remove();\n const error = await response.json().catch(() => ({ error: 'Request failed' }));\n this.addMessage('assistant', `Sorry, I encountered an error: ${error.error || 'Request failed'}`);\n return;\n }\n\n // Remove typing indicator and create streaming message element\n typing.remove();\n const messageEl = document.createElement('div');\n messageEl.className = 'librebot-message assistant';\n this.messagesContainer?.appendChild(messageEl);\n\n const reader = response.body?.getReader();\n if (!reader) {\n this.addMessage('assistant', 'Sorry, streaming is not supported.');\n return;\n }\n\n const decoder = new TextDecoder();\n let fullContent = '';\n\n try {\n while (true) {\n const { done, value } = await reader.read();\n if (done) break;\n\n const chunk = decoder.decode(value, { stream: true });\n const lines = chunk.split('\\n').filter((line) => line.trim() !== '');\n\n for (const line of lines) {\n if (line.startsWith('data: ')) {\n const data = line.slice(6);\n if (data === '[DONE]') continue;\n\n try {\n const parsed = JSON.parse(data);\n if (parsed.content) {\n fullContent += parsed.content;\n messageEl.innerHTML = this.formatMessage(fullContent);\n this.scrollToBottom();\n }\n } catch {\n // Skip malformed JSON\n }\n }\n }\n }\n } catch (error) {\n console.error('Stream reading error:', error);\n }\n\n // Add to messages array\n this.messages.push({\n id: `msg-${Date.now()}`,\n role: 'assistant',\n content: fullContent,\n timestamp: new Date(),\n });\n }\n\n private async callAPI(message: string): Promise<ChatResponse> {\n const response = await fetch(`${this.config.apiUrl}/chat`, {\n method: 'POST',\n headers: {\n 'Content-Type': 'application/json',\n Authorization: `Bearer ${this.config.apiKey}`,\n },\n body: JSON.stringify({\n message,\n context: this.getConversationContext(),\n }),\n });\n\n if (!response.ok) {\n const error = await response.json().catch(() => ({ error: 'Request failed' }));\n return { response: '', error: error.error || 'Request failed' };\n }\n\n return response.json();\n }\n\n private getConversationContext(): Array<{ role: string; content: string }> {\n // Get last 10 messages for context\n return this.messages.slice(-10).map((m) => ({\n role: m.role,\n content: m.content,\n }));\n }\n\n public destroy(): void {\n this.container?.remove();\n document.getElementById('librebot-styles')?.remove();\n }\n}\n"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"librebot.esm.js","sources":["../src/styles.ts","../src/icons.ts","../src/widget.ts"],"sourcesContent":["export const getStyles = (primaryColor: string = '#14b8a6') => `\n .librebot-widget {\n --lb-primary: ${primaryColor};\n --lb-primary-hover: color-mix(in srgb, ${primaryColor} 85%, white);\n --lb-bg: #0f0f0f;\n --lb-bg-secondary: #1a1a1a;\n --lb-text: #ffffff;\n --lb-text-secondary: #9ca3af;\n --lb-border: #2a2a2a;\n font-family: 'Roboto Mono', -apple-system, BlinkMacSystemFont, 'Segoe UI', monospace;\n font-size: 14px;\n line-height: 1.5;\n }\n\n .librebot-widget.light {\n --lb-bg: #ffffff;\n --lb-bg-secondary: #f5f5f5;\n --lb-text: #1a1a1a;\n --lb-text-secondary: #666666;\n --lb-border: #e0e0e0;\n }\n\n .librebot-fab {\n position: fixed;\n bottom: 20px;\n right: 20px;\n width: 56px;\n height: 56px;\n border-radius: 50%;\n background: var(--lb-primary);\n border: none;\n cursor: pointer;\n box-shadow: 0 4px 12px rgba(0, 0, 0, 0.3);\n display: flex;\n align-items: center;\n justify-content: center;\n transition: transform 0.2s, box-shadow 0.2s;\n z-index: 999998;\n }\n\n .librebot-fab:hover {\n transform: scale(1.05);\n box-shadow: 0 6px 16px rgba(0, 0, 0, 0.4);\n }\n\n .librebot-fab svg {\n width: 24px;\n height: 24px;\n fill: white;\n }\n\n .librebot-fab.left {\n right: auto;\n left: 20px;\n }\n\n .librebot-modal {\n position: fixed;\n bottom: 90px;\n right: 20px;\n width: 380px;\n max-width: calc(100vw - 40px);\n height: 520px;\n max-height: calc(100vh - 120px);\n background: var(--lb-bg);\n border: 1px solid var(--lb-border);\n border-radius: 16px;\n box-shadow: 0 8px 32px rgba(0, 0, 0, 0.3);\n display: flex;\n flex-direction: column;\n overflow: hidden;\n z-index: 999999;\n opacity: 0;\n transform: translateY(20px) scale(0.95);\n transition: opacity 0.2s, transform 0.2s;\n pointer-events: none;\n }\n\n .librebot-modal.open {\n opacity: 1;\n transform: translateY(0) scale(1);\n pointer-events: auto;\n }\n\n .librebot-modal.left {\n right: auto;\n left: 20px;\n }\n\n .librebot-header {\n padding: 16px;\n border-bottom: 1px solid var(--lb-border);\n display: flex;\n align-items: center;\n justify-content: space-between;\n }\n\n .librebot-header-content {\n display: flex;\n align-items: center;\n gap: 12px;\n }\n\n .librebot-avatar {\n width: 40px;\n height: 40px;\n border-radius: 10px;\n background: var(--lb-primary);\n display: flex;\n align-items: center;\n justify-content: center;\n }\n\n .librebot-avatar svg {\n width: 24px;\n height: 24px;\n fill: white;\n }\n\n .librebot-title {\n font-weight: 600;\n color: var(--lb-text);\n margin: 0;\n font-size: 16px;\n }\n\n .librebot-subtitle {\n font-size: 12px;\n color: var(--lb-text-secondary);\n margin: 0;\n }\n\n .librebot-close {\n width: 32px;\n height: 32px;\n border-radius: 8px;\n border: none;\n background: transparent;\n cursor: pointer;\n display: flex;\n align-items: center;\n justify-content: center;\n color: var(--lb-text-secondary);\n transition: background 0.2s;\n }\n\n .librebot-close:hover {\n background: var(--lb-bg-secondary);\n }\n\n .librebot-messages {\n flex: 1;\n overflow-y: auto;\n padding: 16px;\n display: flex;\n flex-direction: column;\n gap: 12px;\n }\n\n .librebot-message {\n max-width: 85%;\n padding: 10px 14px;\n border-radius: 16px;\n word-wrap: break-word;\n }\n\n .librebot-message.user {\n align-self: flex-end;\n background: var(--lb-primary);\n color: white;\n border-bottom-right-radius: 4px;\n }\n\n .librebot-message.assistant {\n align-self: flex-start;\n background: var(--lb-bg-secondary);\n color: var(--lb-text);\n border-bottom-left-radius: 4px;\n }\n\n /* Inline code */\n .librebot-inline-code {\n background: rgba(0, 0, 0, 0.3);\n padding: 2px 6px;\n border-radius: 4px;\n font-family: 'Roboto Mono', 'Fira Code', 'Consolas', monospace;\n font-size: 12px;\n color: #f0f0f0;\n }\n\n .librebot-widget.light .librebot-inline-code {\n background: rgba(0, 0, 0, 0.08);\n color: #1a1a1a;\n }\n\n /* Code blocks */\n .librebot-code-block {\n background: #0d1117;\n padding: 12px 14px;\n border-radius: 8px;\n overflow-x: auto;\n margin: 10px 0;\n border: 1px solid rgba(255, 255, 255, 0.1);\n position: relative;\n }\n\n .librebot-widget.light .librebot-code-block {\n background: #f6f8fa;\n border-color: rgba(0, 0, 0, 0.1);\n }\n\n .librebot-code-block code {\n font-family: 'Roboto Mono', 'Fira Code', 'Consolas', monospace;\n font-size: 12px;\n line-height: 1.5;\n color: #e6edf3;\n background: none;\n padding: 0;\n white-space: pre;\n display: block;\n }\n\n .librebot-widget.light .librebot-code-block code {\n color: #24292f;\n }\n\n .librebot-code-block[data-language]::before {\n content: attr(data-language);\n position: absolute;\n top: 6px;\n right: 10px;\n font-size: 10px;\n color: rgba(255, 255, 255, 0.4);\n text-transform: uppercase;\n font-family: 'Roboto Mono', monospace;\n }\n\n .librebot-widget.light .librebot-code-block[data-language]::before {\n color: rgba(0, 0, 0, 0.3);\n }\n\n /* Headers */\n .librebot-h2 {\n font-size: 16px;\n font-weight: 600;\n margin: 12px 0 8px 0;\n color: var(--lb-text);\n }\n\n .librebot-h3 {\n font-size: 14px;\n font-weight: 600;\n margin: 10px 0 6px 0;\n color: var(--lb-text);\n }\n\n .librebot-h4 {\n font-size: 13px;\n font-weight: 600;\n margin: 8px 0 4px 0;\n color: var(--lb-text);\n }\n\n /* Lists */\n .librebot-ul, .librebot-ol {\n margin: 8px 0;\n padding-left: 20px;\n }\n\n .librebot-ul {\n list-style-type: disc;\n }\n\n .librebot-ol {\n list-style-type: decimal;\n }\n\n .librebot-li, .librebot-li-ordered {\n margin: 4px 0;\n padding-left: 4px;\n line-height: 1.5;\n }\n\n /* Links */\n .librebot-link {\n color: var(--lb-primary);\n text-decoration: none;\n border-bottom: 1px solid transparent;\n transition: border-color 0.2s;\n }\n\n .librebot-link:hover {\n border-bottom-color: var(--lb-primary);\n }\n\n /* Blockquotes */\n .librebot-blockquote {\n border-left: 3px solid var(--lb-primary);\n margin: 8px 0;\n padding: 4px 12px;\n color: var(--lb-text-secondary);\n font-style: italic;\n background: rgba(0, 0, 0, 0.1);\n border-radius: 0 6px 6px 0;\n }\n\n .librebot-widget.light .librebot-blockquote {\n background: rgba(0, 0, 0, 0.04);\n }\n\n /* Horizontal rule */\n .librebot-hr {\n border: none;\n border-top: 1px solid var(--lb-border);\n margin: 12px 0;\n }\n\n /* Strong and emphasis */\n .librebot-message strong {\n font-weight: 600;\n }\n\n .librebot-message em {\n font-style: italic;\n }\n\n /* Legacy support for old code elements */\n .librebot-message code:not(.librebot-inline-code) {\n background: rgba(0, 0, 0, 0.2);\n padding: 2px 6px;\n border-radius: 4px;\n font-family: monospace;\n font-size: 13px;\n }\n\n .librebot-message pre:not(.librebot-code-block) {\n background: rgba(0, 0, 0, 0.3);\n padding: 10px;\n border-radius: 8px;\n overflow-x: auto;\n margin: 8px 0;\n }\n\n .librebot-message pre:not(.librebot-code-block) code {\n background: none;\n padding: 0;\n }\n\n .librebot-typing {\n display: flex;\n gap: 4px;\n padding: 12px 16px;\n align-self: flex-start;\n background: var(--lb-bg-secondary);\n border-radius: 16px;\n border-bottom-left-radius: 4px;\n }\n\n .librebot-typing span {\n width: 8px;\n height: 8px;\n background: var(--lb-text-secondary);\n border-radius: 50%;\n animation: librebot-bounce 1.4s infinite ease-in-out;\n }\n\n .librebot-typing span:nth-child(1) { animation-delay: 0s; }\n .librebot-typing span:nth-child(2) { animation-delay: 0.2s; }\n .librebot-typing span:nth-child(3) { animation-delay: 0.4s; }\n\n @keyframes librebot-bounce {\n 0%, 80%, 100% { transform: scale(0.8); opacity: 0.5; }\n 40% { transform: scale(1); opacity: 1; }\n }\n\n .librebot-input-area {\n padding: 12px 16px;\n border-top: 1px solid var(--lb-border);\n display: flex;\n gap: 8px;\n }\n\n .librebot-input {\n flex: 1;\n padding: 10px 14px;\n border: 1px solid var(--lb-border);\n border-radius: 24px;\n background: var(--lb-bg-secondary);\n color: var(--lb-text);\n font-size: 14px;\n outline: none;\n transition: border-color 0.2s;\n }\n\n .librebot-input:focus {\n border-color: var(--lb-primary);\n }\n\n .librebot-input::placeholder {\n color: var(--lb-text-secondary);\n }\n\n .librebot-send {\n width: 40px;\n height: 40px;\n border-radius: 50%;\n border: none;\n background: var(--lb-primary);\n cursor: pointer;\n display: flex;\n align-items: center;\n justify-content: center;\n transition: background 0.2s;\n }\n\n .librebot-send:hover {\n background: var(--lb-primary-hover);\n }\n\n .librebot-send:disabled {\n opacity: 0.5;\n cursor: not-allowed;\n }\n\n .librebot-send svg {\n width: 18px;\n height: 18px;\n fill: white;\n }\n\n .librebot-welcome {\n text-align: center;\n padding: 20px;\n color: var(--lb-text-secondary);\n }\n\n .librebot-welcome-icon {\n width: 48px;\n height: 48px;\n margin: 0 auto 12px;\n background: var(--lb-primary);\n border-radius: 12px;\n display: flex;\n align-items: center;\n justify-content: center;\n }\n\n .librebot-welcome-icon svg {\n width: 28px;\n height: 28px;\n fill: white;\n }\n\n .librebot-powered {\n text-align: center;\n padding: 8px;\n font-size: 11px;\n color: var(--lb-text-secondary);\n border-top: 1px solid var(--lb-border);\n }\n\n .librebot-powered a {\n color: var(--lb-primary);\n text-decoration: none;\n }\n\n .librebot-powered a:hover {\n text-decoration: underline;\n }\n`;\n","export const chatIcon = `<svg viewBox=\"0 0 24 24\" fill=\"none\" stroke=\"currentColor\" stroke-width=\"2\" stroke-linecap=\"round\" stroke-linejoin=\"round\"><path d=\"M21 15a2 2 0 0 1-2 2H7l-4 4V5a2 2 0 0 1 2-2h14a2 2 0 0 1 2 2z\"></path></svg>`;\n\nexport const closeIcon = `<svg viewBox=\"0 0 24 24\" fill=\"none\" stroke=\"currentColor\" stroke-width=\"2\" stroke-linecap=\"round\" stroke-linejoin=\"round\"><line x1=\"18\" y1=\"6\" x2=\"6\" y2=\"18\"></line><line x1=\"6\" y1=\"6\" x2=\"18\" y2=\"18\"></line></svg>`;\n\nexport const sendIcon = `<svg viewBox=\"0 0 24 24\" fill=\"none\" stroke=\"currentColor\" stroke-width=\"2\" stroke-linecap=\"round\" stroke-linejoin=\"round\"><line x1=\"22\" y1=\"2\" x2=\"11\" y2=\"13\"></line><polygon points=\"22 2 15 22 11 13 2 9 22 2\"></polygon></svg>`;\n\nexport const botIcon = `<svg viewBox=\"0 0 24 24\" fill=\"currentColor\"><path d=\"M12 2C6.48 2 2 6.48 2 12s4.48 10 10 10 10-4.48 10-10S17.52 2 12 2zm-2 15l-5-5 1.41-1.41L10 14.17l7.59-7.59L19 8l-9 9z\"/></svg>`;\n","import { LibreBotConfig, Message, ChatResponse } from './types';\nimport { getStyles } from './styles';\nimport { chatIcon, closeIcon, sendIcon } from './icons';\n\nexport class LibreBotWidget {\n private config!: Required<LibreBotConfig>;\n private container: HTMLDivElement | null = null;\n private modal: HTMLDivElement | null = null;\n private messagesContainer: HTMLDivElement | null = null;\n private input: HTMLInputElement | null = null;\n private isOpen = false;\n private messages: Message[] = [];\n private isLoading = false;\n private sessionId: string | null = null;\n\n private defaultConfig: Omit<Required<LibreBotConfig>, 'apiKey'> = {\n apiUrl: 'https://librebot.io/api',\n position: 'bottom-right',\n theme: 'dark',\n primaryColor: '#14b8a6',\n title: 'Libre Bot',\n subtitle: 'AI Documentation Assistant',\n placeholder: 'Ask a question...',\n welcomeMessage: 'Hi! I can help you find answers in the documentation. What would you like to know?',\n streaming: true,\n whiteLabel: false,\n autoLoadConfig: true,\n };\n\n constructor(config: LibreBotConfig) {\n if (!config.apiKey) {\n console.error('LibreBot: API key is required');\n return;\n }\n\n this.config = { ...this.defaultConfig, ...config } as Required<LibreBotConfig>;\n\n // Auto-load config from server if enabled and no custom settings provided\n if (this.config.autoLoadConfig) {\n this.loadRemoteConfig().then(() => this.init());\n } else {\n this.init();\n }\n }\n\n private async loadRemoteConfig(): Promise<void> {\n try {\n const response = await fetch(`${this.config.apiUrl}/widget-config?key=${this.config.apiKey}`);\n if (response.ok) {\n const remoteConfig = await response.json();\n // Merge remote config with local config (local overrides remote)\n this.config = {\n ...this.defaultConfig,\n ...remoteConfig,\n ...this.getProvidedConfig(),\n apiKey: this.config.apiKey,\n apiUrl: this.config.apiUrl,\n autoLoadConfig: this.config.autoLoadConfig,\n } as Required<LibreBotConfig>;\n }\n } catch (error) {\n console.warn('LibreBot: Could not load remote config, using defaults', error);\n }\n }\n\n private getProvidedConfig(): Partial<LibreBotConfig> {\n // Return only the config options that were explicitly provided (not default values)\n const provided: Partial<LibreBotConfig> = {};\n const userConfig = this.config;\n const defaults = this.defaultConfig;\n\n if (userConfig.position !== defaults.position) provided.position = userConfig.position;\n if (userConfig.theme !== defaults.theme) provided.theme = userConfig.theme;\n if (userConfig.primaryColor !== defaults.primaryColor) provided.primaryColor = userConfig.primaryColor;\n if (userConfig.title !== defaults.title) provided.title = userConfig.title;\n if (userConfig.subtitle !== defaults.subtitle) provided.subtitle = userConfig.subtitle;\n if (userConfig.placeholder !== defaults.placeholder) provided.placeholder = userConfig.placeholder;\n if (userConfig.welcomeMessage !== defaults.welcomeMessage) provided.welcomeMessage = userConfig.welcomeMessage;\n if (userConfig.streaming !== defaults.streaming) provided.streaming = userConfig.streaming;\n if (userConfig.whiteLabel !== defaults.whiteLabel) provided.whiteLabel = userConfig.whiteLabel;\n\n return provided;\n }\n\n private init(): void {\n // Load sessionId from localStorage for persistent memory\n this.loadSession();\n\n // Inject styles\n this.injectStyles();\n\n // Create widget container\n this.createWidget();\n\n // Add welcome message\n if (this.config.welcomeMessage) {\n this.addMessage('assistant', this.config.welcomeMessage);\n }\n }\n\n private getSessionKey(): string {\n return `librebot_session_${this.config.apiKey}`;\n }\n\n private loadSession(): void {\n try {\n const stored = localStorage.getItem(this.getSessionKey());\n if (stored) {\n this.sessionId = stored;\n }\n } catch {\n // localStorage may not be available\n }\n }\n\n private saveSession(sessionId: string): void {\n try {\n this.sessionId = sessionId;\n localStorage.setItem(this.getSessionKey(), sessionId);\n } catch {\n // localStorage may not be available\n }\n }\n\n private injectStyles(): void {\n const styleId = 'librebot-styles';\n if (document.getElementById(styleId)) return;\n\n const style = document.createElement('style');\n style.id = styleId;\n style.textContent = getStyles(this.config.primaryColor);\n document.head.appendChild(style);\n }\n\n private createWidget(): void {\n // Create container\n this.container = document.createElement('div');\n this.container.className = `librebot-widget ${this.config.theme === 'light' ? 'light' : ''}`;\n\n // Create FAB button\n const fab = document.createElement('button');\n fab.className = `librebot-fab ${this.config.position === 'bottom-left' ? 'left' : ''}`;\n fab.innerHTML = chatIcon;\n fab.onclick = () => this.toggle();\n\n // Create modal\n this.modal = document.createElement('div');\n this.modal.className = `librebot-modal ${this.config.position === 'bottom-left' ? 'left' : ''}`;\n this.modal.innerHTML = this.getModalHTML();\n\n // Add to container\n this.container.appendChild(fab);\n this.container.appendChild(this.modal);\n document.body.appendChild(this.container);\n\n // Get references\n this.messagesContainer = this.modal.querySelector('.librebot-messages');\n this.input = this.modal.querySelector('.librebot-input');\n\n // Add event listeners\n const closeBtn = this.modal.querySelector('.librebot-close');\n closeBtn?.addEventListener('click', () => this.close());\n\n const sendBtn = this.modal.querySelector('.librebot-send');\n sendBtn?.addEventListener('click', () => this.sendMessage());\n\n this.input?.addEventListener('keypress', (e) => {\n if (e.key === 'Enter' && !e.shiftKey) {\n e.preventDefault();\n this.sendMessage();\n }\n });\n\n // Auto theme detection\n if (this.config.theme === 'auto') {\n const mediaQuery = window.matchMedia('(prefers-color-scheme: light)');\n this.updateTheme(mediaQuery.matches);\n mediaQuery.addEventListener('change', (e) => this.updateTheme(e.matches));\n }\n }\n\n private getModalHTML(): string {\n const poweredByHtml = this.config.whiteLabel\n ? ''\n : `<div class=\"librebot-powered\">\n Powered by <a href=\"https://librebot.io\" target=\"_blank\">Libre Bot</a>\n </div>`;\n\n return `\n <div class=\"librebot-header\">\n <div class=\"librebot-header-content\">\n <div class=\"librebot-avatar\">${chatIcon}</div>\n <div>\n <h3 class=\"librebot-title\">${this.config.title}</h3>\n <p class=\"librebot-subtitle\">${this.config.subtitle}</p>\n </div>\n </div>\n <button class=\"librebot-close\">${closeIcon}</button>\n </div>\n <div class=\"librebot-messages\"></div>\n <div class=\"librebot-input-area\">\n <input type=\"text\" class=\"librebot-input\" placeholder=\"${this.config.placeholder}\" />\n <button class=\"librebot-send\">${sendIcon}</button>\n </div>\n ${poweredByHtml}\n `;\n }\n\n private updateTheme(isLight: boolean): void {\n if (isLight) {\n this.container?.classList.add('light');\n } else {\n this.container?.classList.remove('light');\n }\n }\n\n public toggle(): void {\n this.isOpen ? this.close() : this.open();\n }\n\n public open(): void {\n this.isOpen = true;\n this.modal?.classList.add('open');\n this.input?.focus();\n }\n\n public close(): void {\n this.isOpen = false;\n this.modal?.classList.remove('open');\n }\n\n private addMessage(role: 'user' | 'assistant', content: string): void {\n const message: Message = {\n id: `msg-${Date.now()}`,\n role,\n content,\n timestamp: new Date(),\n };\n\n this.messages.push(message);\n this.renderMessage(message);\n }\n\n private renderMessage(message: Message): void {\n if (!this.messagesContainer) return;\n\n const el = document.createElement('div');\n el.className = `librebot-message ${message.role}`;\n el.innerHTML = this.formatMessage(message.content);\n\n this.messagesContainer.appendChild(el);\n this.scrollToBottom();\n }\n\n private formatMessage(content: string): string {\n // Escape HTML to prevent XSS\n const escapeHtml = (text: string): string => {\n return text\n .replace(/&/g, '&amp;')\n .replace(/</g, '&lt;')\n .replace(/>/g, '&gt;')\n .replace(/\"/g, '&quot;')\n .replace(/'/g, '&#039;');\n };\n\n // First, extract code blocks to protect them from other formatting\n // Regex handles optional space/newline after ``` and optional language identifier\n const codeBlocks: string[] = [];\n let processed = content.replace(/```\\s*(\\w*)\\s*\\n?([\\s\\S]*?)```/g, (_, lang, code) => {\n const escaped = escapeHtml(code.trim());\n const langClass = lang ? ` data-language=\"${escapeHtml(lang)}\"` : '';\n codeBlocks.push(`<pre class=\"librebot-code-block\"${langClass}><code>${escaped}</code></pre>`);\n return `%%CODEBLOCK${codeBlocks.length - 1}%%`;\n });\n\n // Extract inline code\n const inlineCodes: string[] = [];\n processed = processed.replace(/`([^`]+)`/g, (_, code) => {\n inlineCodes.push(`<code class=\"librebot-inline-code\">${escapeHtml(code)}</code>`);\n return `%%INLINECODE${inlineCodes.length - 1}%%`;\n });\n\n // Now escape remaining HTML\n processed = escapeHtml(processed);\n\n // Headers (## and ###)\n processed = processed.replace(/^### (.+)$/gm, '<h4 class=\"librebot-h4\">$1</h4>');\n processed = processed.replace(/^## (.+)$/gm, '<h3 class=\"librebot-h3\">$1</h3>');\n processed = processed.replace(/^# (.+)$/gm, '<h2 class=\"librebot-h2\">$1</h2>');\n\n // Bold and italic\n processed = processed.replace(/\\*\\*\\*([^*]+)\\*\\*\\*/g, '<strong><em>$1</em></strong>');\n processed = processed.replace(/\\*\\*([^*]+)\\*\\*/g, '<strong>$1</strong>');\n processed = processed.replace(/\\*([^*]+)\\*/g, '<em>$1</em>');\n processed = processed.replace(/_([^_]+)_/g, '<em>$1</em>');\n\n // Links [text](url)\n processed = processed.replace(/\\[([^\\]]+)\\]\\(([^)]+)\\)/g, '<a href=\"$2\" target=\"_blank\" rel=\"noopener noreferrer\" class=\"librebot-link\">$1</a>');\n\n // Unordered lists\n processed = processed.replace(/^[\\*\\-] (.+)$/gm, '<li class=\"librebot-li\">$1</li>');\n processed = processed.replace(/(<li class=\"librebot-li\">.*<\\/li>\\n?)+/g, (match) => {\n return `<ul class=\"librebot-ul\">${match}</ul>`;\n });\n\n // Ordered lists\n processed = processed.replace(/^\\d+\\. (.+)$/gm, '<li class=\"librebot-li-ordered\">$1</li>');\n processed = processed.replace(/(<li class=\"librebot-li-ordered\">.*<\\/li>\\n?)+/g, (match) => {\n return `<ol class=\"librebot-ol\">${match}</ol>`;\n });\n\n // Horizontal rule\n processed = processed.replace(/^---$/gm, '<hr class=\"librebot-hr\">');\n\n // Blockquotes\n processed = processed.replace(/^&gt; (.+)$/gm, '<blockquote class=\"librebot-blockquote\">$1</blockquote>');\n\n // Convert newlines to <br> (but not inside lists/blockquotes)\n processed = processed.replace(/\\n/g, '<br>');\n\n // Clean up extra <br> after block elements\n processed = processed.replace(/<\\/(pre|ul|ol|blockquote|h[2-4])><br>/g, '</$1>');\n processed = processed.replace(/<br><(pre|ul|ol|blockquote|h[2-4])/g, '<$1');\n\n // Restore code blocks\n codeBlocks.forEach((block, i) => {\n processed = processed.replace(`%%CODEBLOCK${i}%%`, block);\n });\n\n // Restore inline code\n inlineCodes.forEach((code, i) => {\n processed = processed.replace(`%%INLINECODE${i}%%`, code);\n });\n\n return processed;\n }\n\n private showTyping(): HTMLDivElement {\n const typing = document.createElement('div');\n typing.className = 'librebot-typing';\n typing.innerHTML = '<span></span><span></span><span></span>';\n this.messagesContainer?.appendChild(typing);\n this.scrollToBottom();\n return typing;\n }\n\n private scrollToBottom(): void {\n if (this.messagesContainer) {\n this.messagesContainer.scrollTop = this.messagesContainer.scrollHeight;\n }\n }\n\n private async sendMessage(): Promise<void> {\n if (!this.input || this.isLoading) return;\n\n const content = this.input.value.trim();\n if (!content) return;\n\n // Add user message\n this.addMessage('user', content);\n this.input.value = '';\n\n // Show typing indicator\n this.isLoading = true;\n const typing = this.showTyping();\n\n try {\n if (this.config.streaming) {\n await this.callStreamingAPI(content, typing);\n } else {\n const response = await this.callAPI(content);\n typing.remove();\n\n if (response.error) {\n this.addMessage('assistant', `Sorry, I encountered an error: ${response.error}`);\n } else {\n this.addMessage('assistant', response.response);\n }\n }\n } catch (error) {\n typing.remove();\n this.addMessage('assistant', 'Sorry, I had trouble connecting. Please try again.');\n console.error('LibreBot error:', error);\n } finally {\n this.isLoading = false;\n }\n }\n\n private async callStreamingAPI(message: string, typing: HTMLDivElement): Promise<void> {\n const response = await fetch(`${this.config.apiUrl}/chat`, {\n method: 'POST',\n headers: {\n 'Content-Type': 'application/json',\n Authorization: `Bearer ${this.config.apiKey}`,\n },\n body: JSON.stringify({\n message,\n context: this.getConversationContext(),\n stream: true,\n sessionId: this.sessionId,\n }),\n });\n\n if (!response.ok) {\n typing.remove();\n const error = await response.json().catch(() => ({ error: 'Request failed' }));\n this.addMessage('assistant', `Sorry, I encountered an error: ${error.error || 'Request failed'}`);\n return;\n }\n\n // Remove typing indicator and create streaming message element\n typing.remove();\n const messageEl = document.createElement('div');\n messageEl.className = 'librebot-message assistant';\n this.messagesContainer?.appendChild(messageEl);\n\n const reader = response.body?.getReader();\n if (!reader) {\n this.addMessage('assistant', 'Sorry, streaming is not supported.');\n return;\n }\n\n const decoder = new TextDecoder();\n let fullContent = '';\n\n try {\n while (true) {\n const { done, value } = await reader.read();\n if (done) break;\n\n const chunk = decoder.decode(value, { stream: true });\n const lines = chunk.split('\\n').filter((line) => line.trim() !== '');\n\n for (const line of lines) {\n if (line.startsWith('data: ')) {\n const data = line.slice(6);\n if (data === '[DONE]') continue;\n\n try {\n const parsed = JSON.parse(data);\n if (parsed.content) {\n fullContent += parsed.content;\n messageEl.innerHTML = this.formatMessage(fullContent);\n this.scrollToBottom();\n }\n // Save sessionId when received from server\n if (parsed.sessionId) {\n this.saveSession(parsed.sessionId);\n }\n } catch {\n // Skip malformed JSON\n }\n }\n }\n }\n } catch (error) {\n console.error('Stream reading error:', error);\n }\n\n // Add to messages array\n this.messages.push({\n id: `msg-${Date.now()}`,\n role: 'assistant',\n content: fullContent,\n timestamp: new Date(),\n });\n }\n\n private async callAPI(message: string): Promise<ChatResponse> {\n const response = await fetch(`${this.config.apiUrl}/chat`, {\n method: 'POST',\n headers: {\n 'Content-Type': 'application/json',\n Authorization: `Bearer ${this.config.apiKey}`,\n },\n body: JSON.stringify({\n message,\n context: this.getConversationContext(),\n sessionId: this.sessionId,\n }),\n });\n\n if (!response.ok) {\n const error = await response.json().catch(() => ({ error: 'Request failed' }));\n return { response: '', error: error.error || 'Request failed' };\n }\n\n const data = await response.json();\n // Save sessionId when received from server\n if (data.sessionId) {\n this.saveSession(data.sessionId);\n }\n return data;\n }\n\n private getConversationContext(): Array<{ role: string; content: string }> {\n // Get last 10 messages for context\n return this.messages.slice(-10).map((m) => ({\n role: m.role,\n content: m.content,\n }));\n }\n\n public destroy(): void {\n this.container?.remove();\n document.getElementById('librebot-styles')?.remove();\n }\n\n public clearSession(): void {\n try {\n this.sessionId = null;\n this.messages = [];\n localStorage.removeItem(this.getSessionKey());\n if (this.messagesContainer) {\n this.messagesContainer.innerHTML = '';\n }\n // Re-add welcome message\n if (this.config.welcomeMessage) {\n this.addMessage('assistant', this.config.welcomeMessage);\n }\n } catch {\n // localStorage may not be available\n }\n }\n}\n"],"names":[],"mappings":"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"}
package/dist/librebot.js CHANGED
@@ -1,2 +1,2 @@
1
- var LibreBot=function(e){"use strict";const n='<svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><path d="M21 15a2 2 0 0 1-2 2H7l-4 4V5a2 2 0 0 1 2-2h14a2 2 0 0 1 2 2z"></path></svg>';class t{constructor(e){this.container=null,this.modal=null,this.messagesContainer=null,this.input=null,this.isOpen=!1,this.messages=[],this.isLoading=!1,this.defaultConfig={apiUrl:"https://librebot.io/api",position:"bottom-right",theme:"dark",primaryColor:"#14b8a6",title:"Libre Bot",subtitle:"AI Documentation Assistant",placeholder:"Ask a question...",welcomeMessage:"Hi! I can help you find answers in the documentation. What would you like to know?",streaming:!0,whiteLabel:!1,autoLoadConfig:!0},e.apiKey?(this.config={...this.defaultConfig,...e},this.config.autoLoadConfig?this.loadRemoteConfig().then(()=>this.init()):this.init()):console.error("LibreBot: API key is required")}async loadRemoteConfig(){try{const e=await fetch(`${this.config.apiUrl}/widget-config?key=${this.config.apiKey}`);if(e.ok){const n=await e.json();this.config={...this.defaultConfig,...n,...this.getProvidedConfig(),apiKey:this.config.apiKey,apiUrl:this.config.apiUrl,autoLoadConfig:this.config.autoLoadConfig}}}catch(e){console.warn("LibreBot: Could not load remote config, using defaults",e)}}getProvidedConfig(){const e={},n=this.config,t=this.defaultConfig;return n.position!==t.position&&(e.position=n.position),n.theme!==t.theme&&(e.theme=n.theme),n.primaryColor!==t.primaryColor&&(e.primaryColor=n.primaryColor),n.title!==t.title&&(e.title=n.title),n.subtitle!==t.subtitle&&(e.subtitle=n.subtitle),n.placeholder!==t.placeholder&&(e.placeholder=n.placeholder),n.welcomeMessage!==t.welcomeMessage&&(e.welcomeMessage=n.welcomeMessage),n.streaming!==t.streaming&&(e.streaming=n.streaming),n.whiteLabel!==t.whiteLabel&&(e.whiteLabel=n.whiteLabel),e}init(){this.injectStyles(),this.createWidget(),this.config.welcomeMessage&&this.addMessage("assistant",this.config.welcomeMessage)}injectStyles(){const e="librebot-styles";if(document.getElementById(e))return;const n=document.createElement("style");n.id=e,n.textContent=((e="#14b8a6")=>`\n .librebot-widget {\n --lb-primary: ${e};\n --lb-primary-hover: color-mix(in srgb, ${e} 85%, white);\n --lb-bg: #0f0f0f;\n --lb-bg-secondary: #1a1a1a;\n --lb-text: #ffffff;\n --lb-text-secondary: #9ca3af;\n --lb-border: #2a2a2a;\n font-family: 'Roboto Mono', -apple-system, BlinkMacSystemFont, 'Segoe UI', monospace;\n font-size: 14px;\n line-height: 1.5;\n }\n\n .librebot-widget.light {\n --lb-bg: #ffffff;\n --lb-bg-secondary: #f5f5f5;\n --lb-text: #1a1a1a;\n --lb-text-secondary: #666666;\n --lb-border: #e0e0e0;\n }\n\n .librebot-fab {\n position: fixed;\n bottom: 20px;\n right: 20px;\n width: 56px;\n height: 56px;\n border-radius: 50%;\n background: var(--lb-primary);\n border: none;\n cursor: pointer;\n box-shadow: 0 4px 12px rgba(0, 0, 0, 0.3);\n display: flex;\n align-items: center;\n justify-content: center;\n transition: transform 0.2s, box-shadow 0.2s;\n z-index: 999998;\n }\n\n .librebot-fab:hover {\n transform: scale(1.05);\n box-shadow: 0 6px 16px rgba(0, 0, 0, 0.4);\n }\n\n .librebot-fab svg {\n width: 24px;\n height: 24px;\n fill: white;\n }\n\n .librebot-fab.left {\n right: auto;\n left: 20px;\n }\n\n .librebot-modal {\n position: fixed;\n bottom: 90px;\n right: 20px;\n width: 380px;\n max-width: calc(100vw - 40px);\n height: 520px;\n max-height: calc(100vh - 120px);\n background: var(--lb-bg);\n border: 1px solid var(--lb-border);\n border-radius: 16px;\n box-shadow: 0 8px 32px rgba(0, 0, 0, 0.3);\n display: flex;\n flex-direction: column;\n overflow: hidden;\n z-index: 999999;\n opacity: 0;\n transform: translateY(20px) scale(0.95);\n transition: opacity 0.2s, transform 0.2s;\n pointer-events: none;\n }\n\n .librebot-modal.open {\n opacity: 1;\n transform: translateY(0) scale(1);\n pointer-events: auto;\n }\n\n .librebot-modal.left {\n right: auto;\n left: 20px;\n }\n\n .librebot-header {\n padding: 16px;\n border-bottom: 1px solid var(--lb-border);\n display: flex;\n align-items: center;\n justify-content: space-between;\n }\n\n .librebot-header-content {\n display: flex;\n align-items: center;\n gap: 12px;\n }\n\n .librebot-avatar {\n width: 40px;\n height: 40px;\n border-radius: 10px;\n background: var(--lb-primary);\n display: flex;\n align-items: center;\n justify-content: center;\n }\n\n .librebot-avatar svg {\n width: 24px;\n height: 24px;\n fill: white;\n }\n\n .librebot-title {\n font-weight: 600;\n color: var(--lb-text);\n margin: 0;\n font-size: 16px;\n }\n\n .librebot-subtitle {\n font-size: 12px;\n color: var(--lb-text-secondary);\n margin: 0;\n }\n\n .librebot-close {\n width: 32px;\n height: 32px;\n border-radius: 8px;\n border: none;\n background: transparent;\n cursor: pointer;\n display: flex;\n align-items: center;\n justify-content: center;\n color: var(--lb-text-secondary);\n transition: background 0.2s;\n }\n\n .librebot-close:hover {\n background: var(--lb-bg-secondary);\n }\n\n .librebot-messages {\n flex: 1;\n overflow-y: auto;\n padding: 16px;\n display: flex;\n flex-direction: column;\n gap: 12px;\n }\n\n .librebot-message {\n max-width: 85%;\n padding: 10px 14px;\n border-radius: 16px;\n word-wrap: break-word;\n }\n\n .librebot-message.user {\n align-self: flex-end;\n background: var(--lb-primary);\n color: white;\n border-bottom-right-radius: 4px;\n }\n\n .librebot-message.assistant {\n align-self: flex-start;\n background: var(--lb-bg-secondary);\n color: var(--lb-text);\n border-bottom-left-radius: 4px;\n }\n\n /* Inline code */\n .librebot-inline-code {\n background: rgba(0, 0, 0, 0.3);\n padding: 2px 6px;\n border-radius: 4px;\n font-family: 'Roboto Mono', 'Fira Code', 'Consolas', monospace;\n font-size: 12px;\n color: #f0f0f0;\n }\n\n .librebot-widget.light .librebot-inline-code {\n background: rgba(0, 0, 0, 0.08);\n color: #1a1a1a;\n }\n\n /* Code blocks */\n .librebot-code-block {\n background: #0d1117;\n padding: 12px 14px;\n border-radius: 8px;\n overflow-x: auto;\n margin: 10px 0;\n border: 1px solid rgba(255, 255, 255, 0.1);\n position: relative;\n }\n\n .librebot-widget.light .librebot-code-block {\n background: #f6f8fa;\n border-color: rgba(0, 0, 0, 0.1);\n }\n\n .librebot-code-block code {\n font-family: 'Roboto Mono', 'Fira Code', 'Consolas', monospace;\n font-size: 12px;\n line-height: 1.5;\n color: #e6edf3;\n background: none;\n padding: 0;\n white-space: pre;\n display: block;\n }\n\n .librebot-widget.light .librebot-code-block code {\n color: #24292f;\n }\n\n .librebot-code-block[data-language]::before {\n content: attr(data-language);\n position: absolute;\n top: 6px;\n right: 10px;\n font-size: 10px;\n color: rgba(255, 255, 255, 0.4);\n text-transform: uppercase;\n font-family: 'Roboto Mono', monospace;\n }\n\n .librebot-widget.light .librebot-code-block[data-language]::before {\n color: rgba(0, 0, 0, 0.3);\n }\n\n /* Headers */\n .librebot-h2 {\n font-size: 16px;\n font-weight: 600;\n margin: 12px 0 8px 0;\n color: var(--lb-text);\n }\n\n .librebot-h3 {\n font-size: 14px;\n font-weight: 600;\n margin: 10px 0 6px 0;\n color: var(--lb-text);\n }\n\n .librebot-h4 {\n font-size: 13px;\n font-weight: 600;\n margin: 8px 0 4px 0;\n color: var(--lb-text);\n }\n\n /* Lists */\n .librebot-ul, .librebot-ol {\n margin: 8px 0;\n padding-left: 20px;\n }\n\n .librebot-ul {\n list-style-type: disc;\n }\n\n .librebot-ol {\n list-style-type: decimal;\n }\n\n .librebot-li, .librebot-li-ordered {\n margin: 4px 0;\n padding-left: 4px;\n line-height: 1.5;\n }\n\n /* Links */\n .librebot-link {\n color: var(--lb-primary);\n text-decoration: none;\n border-bottom: 1px solid transparent;\n transition: border-color 0.2s;\n }\n\n .librebot-link:hover {\n border-bottom-color: var(--lb-primary);\n }\n\n /* Blockquotes */\n .librebot-blockquote {\n border-left: 3px solid var(--lb-primary);\n margin: 8px 0;\n padding: 4px 12px;\n color: var(--lb-text-secondary);\n font-style: italic;\n background: rgba(0, 0, 0, 0.1);\n border-radius: 0 6px 6px 0;\n }\n\n .librebot-widget.light .librebot-blockquote {\n background: rgba(0, 0, 0, 0.04);\n }\n\n /* Horizontal rule */\n .librebot-hr {\n border: none;\n border-top: 1px solid var(--lb-border);\n margin: 12px 0;\n }\n\n /* Strong and emphasis */\n .librebot-message strong {\n font-weight: 600;\n }\n\n .librebot-message em {\n font-style: italic;\n }\n\n /* Legacy support for old code elements */\n .librebot-message code:not(.librebot-inline-code) {\n background: rgba(0, 0, 0, 0.2);\n padding: 2px 6px;\n border-radius: 4px;\n font-family: monospace;\n font-size: 13px;\n }\n\n .librebot-message pre:not(.librebot-code-block) {\n background: rgba(0, 0, 0, 0.3);\n padding: 10px;\n border-radius: 8px;\n overflow-x: auto;\n margin: 8px 0;\n }\n\n .librebot-message pre:not(.librebot-code-block) code {\n background: none;\n padding: 0;\n }\n\n .librebot-typing {\n display: flex;\n gap: 4px;\n padding: 12px 16px;\n align-self: flex-start;\n background: var(--lb-bg-secondary);\n border-radius: 16px;\n border-bottom-left-radius: 4px;\n }\n\n .librebot-typing span {\n width: 8px;\n height: 8px;\n background: var(--lb-text-secondary);\n border-radius: 50%;\n animation: librebot-bounce 1.4s infinite ease-in-out;\n }\n\n .librebot-typing span:nth-child(1) { animation-delay: 0s; }\n .librebot-typing span:nth-child(2) { animation-delay: 0.2s; }\n .librebot-typing span:nth-child(3) { animation-delay: 0.4s; }\n\n @keyframes librebot-bounce {\n 0%, 80%, 100% { transform: scale(0.8); opacity: 0.5; }\n 40% { transform: scale(1); opacity: 1; }\n }\n\n .librebot-input-area {\n padding: 12px 16px;\n border-top: 1px solid var(--lb-border);\n display: flex;\n gap: 8px;\n }\n\n .librebot-input {\n flex: 1;\n padding: 10px 14px;\n border: 1px solid var(--lb-border);\n border-radius: 24px;\n background: var(--lb-bg-secondary);\n color: var(--lb-text);\n font-size: 14px;\n outline: none;\n transition: border-color 0.2s;\n }\n\n .librebot-input:focus {\n border-color: var(--lb-primary);\n }\n\n .librebot-input::placeholder {\n color: var(--lb-text-secondary);\n }\n\n .librebot-send {\n width: 40px;\n height: 40px;\n border-radius: 50%;\n border: none;\n background: var(--lb-primary);\n cursor: pointer;\n display: flex;\n align-items: center;\n justify-content: center;\n transition: background 0.2s;\n }\n\n .librebot-send:hover {\n background: var(--lb-primary-hover);\n }\n\n .librebot-send:disabled {\n opacity: 0.5;\n cursor: not-allowed;\n }\n\n .librebot-send svg {\n width: 18px;\n height: 18px;\n fill: white;\n }\n\n .librebot-welcome {\n text-align: center;\n padding: 20px;\n color: var(--lb-text-secondary);\n }\n\n .librebot-welcome-icon {\n width: 48px;\n height: 48px;\n margin: 0 auto 12px;\n background: var(--lb-primary);\n border-radius: 12px;\n display: flex;\n align-items: center;\n justify-content: center;\n }\n\n .librebot-welcome-icon svg {\n width: 28px;\n height: 28px;\n fill: white;\n }\n\n .librebot-powered {\n text-align: center;\n padding: 8px;\n font-size: 11px;\n color: var(--lb-text-secondary);\n border-top: 1px solid var(--lb-border);\n }\n\n .librebot-powered a {\n color: var(--lb-primary);\n text-decoration: none;\n }\n\n .librebot-powered a:hover {\n text-decoration: underline;\n }\n`)(this.config.primaryColor),document.head.appendChild(n)}createWidget(){this.container=document.createElement("div"),this.container.className="librebot-widget "+("light"===this.config.theme?"light":"");const e=document.createElement("button");e.className="librebot-fab "+("bottom-left"===this.config.position?"left":""),e.innerHTML=n,e.onclick=()=>this.toggle(),this.modal=document.createElement("div"),this.modal.className="librebot-modal "+("bottom-left"===this.config.position?"left":""),this.modal.innerHTML=this.getModalHTML(),this.container.appendChild(e),this.container.appendChild(this.modal),document.body.appendChild(this.container),this.messagesContainer=this.modal.querySelector(".librebot-messages"),this.input=this.modal.querySelector(".librebot-input");const t=this.modal.querySelector(".librebot-close");t?.addEventListener("click",()=>this.close());const o=this.modal.querySelector(".librebot-send");if(o?.addEventListener("click",()=>this.sendMessage()),this.input?.addEventListener("keypress",e=>{"Enter"!==e.key||e.shiftKey||(e.preventDefault(),this.sendMessage())}),"auto"===this.config.theme){const e=window.matchMedia("(prefers-color-scheme: light)");this.updateTheme(e.matches),e.addEventListener("change",e=>this.updateTheme(e.matches))}}getModalHTML(){const e=this.config.whiteLabel?"":'<div class="librebot-powered">\n Powered by <a href="https://librebot.io" target="_blank">Libre Bot</a>\n </div>';return`\n <div class="librebot-header">\n <div class="librebot-header-content">\n <div class="librebot-avatar">${n}</div>\n <div>\n <h3 class="librebot-title">${this.config.title}</h3>\n <p class="librebot-subtitle">${this.config.subtitle}</p>\n </div>\n </div>\n <button class="librebot-close"><svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><line x1="18" y1="6" x2="6" y2="18"></line><line x1="6" y1="6" x2="18" y2="18"></line></svg></button>\n </div>\n <div class="librebot-messages"></div>\n <div class="librebot-input-area">\n <input type="text" class="librebot-input" placeholder="${this.config.placeholder}" />\n <button class="librebot-send"><svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><line x1="22" y1="2" x2="11" y2="13"></line><polygon points="22 2 15 22 11 13 2 9 22 2"></polygon></svg></button>\n </div>\n ${e}\n `}updateTheme(e){e?this.container?.classList.add("light"):this.container?.classList.remove("light")}toggle(){this.isOpen?this.close():this.open()}open(){this.isOpen=!0,this.modal?.classList.add("open"),this.input?.focus()}close(){this.isOpen=!1,this.modal?.classList.remove("open")}addMessage(e,n){const t={id:`msg-${Date.now()}`,role:e,content:n,timestamp:new Date};this.messages.push(t),this.renderMessage(t)}renderMessage(e){if(!this.messagesContainer)return;const n=document.createElement("div");n.className=`librebot-message ${e.role}`,n.innerHTML=this.formatMessage(e.content),this.messagesContainer.appendChild(n),this.scrollToBottom()}formatMessage(e){const n=e=>e.replace(/&/g,"&amp;").replace(/</g,"&lt;").replace(/>/g,"&gt;").replace(/"/g,"&quot;").replace(/'/g,"&#039;"),t=[];let o=e.replace(/```\s*(\w*)\s*\n?([\s\S]*?)```/g,(e,o,i)=>{const r=n(i.trim()),a=o?` data-language="${n(o)}"`:"";return t.push(`<pre class="librebot-code-block"${a}><code>${r}</code></pre>`),`%%CODEBLOCK${t.length-1}%%`});const i=[];return o=o.replace(/`([^`]+)`/g,(e,t)=>(i.push(`<code class="librebot-inline-code">${n(t)}</code>`),`%%INLINECODE${i.length-1}%%`)),o=n(o),o=o.replace(/^### (.+)$/gm,'<h4 class="librebot-h4">$1</h4>'),o=o.replace(/^## (.+)$/gm,'<h3 class="librebot-h3">$1</h3>'),o=o.replace(/^# (.+)$/gm,'<h2 class="librebot-h2">$1</h2>'),o=o.replace(/\*\*\*([^*]+)\*\*\*/g,"<strong><em>$1</em></strong>"),o=o.replace(/\*\*([^*]+)\*\*/g,"<strong>$1</strong>"),o=o.replace(/\*([^*]+)\*/g,"<em>$1</em>"),o=o.replace(/_([^_]+)_/g,"<em>$1</em>"),o=o.replace(/\[([^\]]+)\]\(([^)]+)\)/g,'<a href="$2" target="_blank" rel="noopener noreferrer" class="librebot-link">$1</a>'),o=o.replace(/^[\*\-] (.+)$/gm,'<li class="librebot-li">$1</li>'),o=o.replace(/(<li class="librebot-li">.*<\/li>\n?)+/g,e=>`<ul class="librebot-ul">${e}</ul>`),o=o.replace(/^\d+\. (.+)$/gm,'<li class="librebot-li-ordered">$1</li>'),o=o.replace(/(<li class="librebot-li-ordered">.*<\/li>\n?)+/g,e=>`<ol class="librebot-ol">${e}</ol>`),o=o.replace(/^---$/gm,'<hr class="librebot-hr">'),o=o.replace(/^&gt; (.+)$/gm,'<blockquote class="librebot-blockquote">$1</blockquote>'),o=o.replace(/\n/g,"<br>"),o=o.replace(/<\/(pre|ul|ol|blockquote|h[2-4])><br>/g,"</$1>"),o=o.replace(/<br><(pre|ul|ol|blockquote|h[2-4])/g,"<$1"),t.forEach((e,n)=>{o=o.replace(`%%CODEBLOCK${n}%%`,e)}),i.forEach((e,n)=>{o=o.replace(`%%INLINECODE${n}%%`,e)}),o}showTyping(){const e=document.createElement("div");return e.className="librebot-typing",e.innerHTML="<span></span><span></span><span></span>",this.messagesContainer?.appendChild(e),this.scrollToBottom(),e}scrollToBottom(){this.messagesContainer&&(this.messagesContainer.scrollTop=this.messagesContainer.scrollHeight)}async sendMessage(){if(!this.input||this.isLoading)return;const e=this.input.value.trim();if(!e)return;this.addMessage("user",e),this.input.value="",this.isLoading=!0;const n=this.showTyping();try{if(this.config.streaming)await this.callStreamingAPI(e,n);else{const t=await this.callAPI(e);n.remove(),t.error?this.addMessage("assistant",`Sorry, I encountered an error: ${t.error}`):this.addMessage("assistant",t.response)}}catch(e){n.remove(),this.addMessage("assistant","Sorry, I had trouble connecting. Please try again."),console.error("LibreBot error:",e)}finally{this.isLoading=!1}}async callStreamingAPI(e,n){const t=await fetch(`${this.config.apiUrl}/chat`,{method:"POST",headers:{"Content-Type":"application/json",Authorization:`Bearer ${this.config.apiKey}`},body:JSON.stringify({message:e,context:this.getConversationContext(),stream:!0})});if(!t.ok){n.remove();const e=await t.json().catch(()=>({error:"Request failed"}));return void this.addMessage("assistant",`Sorry, I encountered an error: ${e.error||"Request failed"}`)}n.remove();const o=document.createElement("div");o.className="librebot-message assistant",this.messagesContainer?.appendChild(o);const i=t.body?.getReader();if(!i)return void this.addMessage("assistant","Sorry, streaming is not supported.");const r=new TextDecoder;let a="";try{for(;;){const{done:e,value:n}=await i.read();if(e)break;const t=r.decode(n,{stream:!0}).split("\n").filter(e=>""!==e.trim());for(const e of t)if(e.startsWith("data: ")){const n=e.slice(6);if("[DONE]"===n)continue;try{const e=JSON.parse(n);e.content&&(a+=e.content,o.innerHTML=this.formatMessage(a),this.scrollToBottom())}catch{}}}}catch(e){console.error("Stream reading error:",e)}this.messages.push({id:`msg-${Date.now()}`,role:"assistant",content:a,timestamp:new Date})}async callAPI(e){const n=await fetch(`${this.config.apiUrl}/chat`,{method:"POST",headers:{"Content-Type":"application/json",Authorization:`Bearer ${this.config.apiKey}`},body:JSON.stringify({message:e,context:this.getConversationContext()})});if(!n.ok){return{response:"",error:(await n.json().catch(()=>({error:"Request failed"}))).error||"Request failed"}}return n.json()}getConversationContext(){return this.messages.slice(-10).map(e=>({role:e.role,content:e.content}))}destroy(){this.container?.remove(),document.getElementById("librebot-styles")?.remove()}}return function(){const e=document.currentScript||document.querySelector('script[data-key][src*="librebot"]');if(!e)return void console.warn("LibreBot: Could not find script tag");const n={apiKey:e.dataset.key||e.dataset.apiKey||"",apiUrl:e.dataset.apiUrl||"https://api.librebot.io",position:e.dataset.position||"bottom-right",theme:e.dataset.theme||"dark",primaryColor:e.dataset.color||"#14b8a6",title:e.dataset.title||"Libre Bot",subtitle:e.dataset.subtitle||"AI Documentation Assistant",placeholder:e.dataset.placeholder||"Ask a question...",welcomeMessage:e.dataset.welcome||"Hi! I can help you find answers in the documentation. What would you like to know?",streaming:"false"!==e.dataset.streaming};n.apiKey?"loading"===document.readyState?document.addEventListener("DOMContentLoaded",()=>{window.LibreBot=new t(n)}):window.LibreBot=new t(n):console.error("LibreBot: Missing data-key attribute")}(),e.LibreBotWidget=t,e}({});
1
+ var LibreBot=function(e){"use strict";const n='<svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><path d="M21 15a2 2 0 0 1-2 2H7l-4 4V5a2 2 0 0 1 2-2h14a2 2 0 0 1 2 2z"></path></svg>';class t{constructor(e){this.container=null,this.modal=null,this.messagesContainer=null,this.input=null,this.isOpen=!1,this.messages=[],this.isLoading=!1,this.sessionId=null,this.defaultConfig={apiUrl:"https://librebot.io/api",position:"bottom-right",theme:"dark",primaryColor:"#14b8a6",title:"Libre Bot",subtitle:"AI Documentation Assistant",placeholder:"Ask a question...",welcomeMessage:"Hi! I can help you find answers in the documentation. What would you like to know?",streaming:!0,whiteLabel:!1,autoLoadConfig:!0},e.apiKey?(this.config={...this.defaultConfig,...e},this.config.autoLoadConfig?this.loadRemoteConfig().then(()=>this.init()):this.init()):console.error("LibreBot: API key is required")}async loadRemoteConfig(){try{const e=await fetch(`${this.config.apiUrl}/widget-config?key=${this.config.apiKey}`);if(e.ok){const n=await e.json();this.config={...this.defaultConfig,...n,...this.getProvidedConfig(),apiKey:this.config.apiKey,apiUrl:this.config.apiUrl,autoLoadConfig:this.config.autoLoadConfig}}}catch(e){console.warn("LibreBot: Could not load remote config, using defaults",e)}}getProvidedConfig(){const e={},n=this.config,t=this.defaultConfig;return n.position!==t.position&&(e.position=n.position),n.theme!==t.theme&&(e.theme=n.theme),n.primaryColor!==t.primaryColor&&(e.primaryColor=n.primaryColor),n.title!==t.title&&(e.title=n.title),n.subtitle!==t.subtitle&&(e.subtitle=n.subtitle),n.placeholder!==t.placeholder&&(e.placeholder=n.placeholder),n.welcomeMessage!==t.welcomeMessage&&(e.welcomeMessage=n.welcomeMessage),n.streaming!==t.streaming&&(e.streaming=n.streaming),n.whiteLabel!==t.whiteLabel&&(e.whiteLabel=n.whiteLabel),e}init(){this.loadSession(),this.injectStyles(),this.createWidget(),this.config.welcomeMessage&&this.addMessage("assistant",this.config.welcomeMessage)}getSessionKey(){return`librebot_session_${this.config.apiKey}`}loadSession(){try{const e=localStorage.getItem(this.getSessionKey());e&&(this.sessionId=e)}catch{}}saveSession(e){try{this.sessionId=e,localStorage.setItem(this.getSessionKey(),e)}catch{}}injectStyles(){const e="librebot-styles";if(document.getElementById(e))return;const n=document.createElement("style");n.id=e,n.textContent=((e="#14b8a6")=>`\n .librebot-widget {\n --lb-primary: ${e};\n --lb-primary-hover: color-mix(in srgb, ${e} 85%, white);\n --lb-bg: #0f0f0f;\n --lb-bg-secondary: #1a1a1a;\n --lb-text: #ffffff;\n --lb-text-secondary: #9ca3af;\n --lb-border: #2a2a2a;\n font-family: 'Roboto Mono', -apple-system, BlinkMacSystemFont, 'Segoe UI', monospace;\n font-size: 14px;\n line-height: 1.5;\n }\n\n .librebot-widget.light {\n --lb-bg: #ffffff;\n --lb-bg-secondary: #f5f5f5;\n --lb-text: #1a1a1a;\n --lb-text-secondary: #666666;\n --lb-border: #e0e0e0;\n }\n\n .librebot-fab {\n position: fixed;\n bottom: 20px;\n right: 20px;\n width: 56px;\n height: 56px;\n border-radius: 50%;\n background: var(--lb-primary);\n border: none;\n cursor: pointer;\n box-shadow: 0 4px 12px rgba(0, 0, 0, 0.3);\n display: flex;\n align-items: center;\n justify-content: center;\n transition: transform 0.2s, box-shadow 0.2s;\n z-index: 999998;\n }\n\n .librebot-fab:hover {\n transform: scale(1.05);\n box-shadow: 0 6px 16px rgba(0, 0, 0, 0.4);\n }\n\n .librebot-fab svg {\n width: 24px;\n height: 24px;\n fill: white;\n }\n\n .librebot-fab.left {\n right: auto;\n left: 20px;\n }\n\n .librebot-modal {\n position: fixed;\n bottom: 90px;\n right: 20px;\n width: 380px;\n max-width: calc(100vw - 40px);\n height: 520px;\n max-height: calc(100vh - 120px);\n background: var(--lb-bg);\n border: 1px solid var(--lb-border);\n border-radius: 16px;\n box-shadow: 0 8px 32px rgba(0, 0, 0, 0.3);\n display: flex;\n flex-direction: column;\n overflow: hidden;\n z-index: 999999;\n opacity: 0;\n transform: translateY(20px) scale(0.95);\n transition: opacity 0.2s, transform 0.2s;\n pointer-events: none;\n }\n\n .librebot-modal.open {\n opacity: 1;\n transform: translateY(0) scale(1);\n pointer-events: auto;\n }\n\n .librebot-modal.left {\n right: auto;\n left: 20px;\n }\n\n .librebot-header {\n padding: 16px;\n border-bottom: 1px solid var(--lb-border);\n display: flex;\n align-items: center;\n justify-content: space-between;\n }\n\n .librebot-header-content {\n display: flex;\n align-items: center;\n gap: 12px;\n }\n\n .librebot-avatar {\n width: 40px;\n height: 40px;\n border-radius: 10px;\n background: var(--lb-primary);\n display: flex;\n align-items: center;\n justify-content: center;\n }\n\n .librebot-avatar svg {\n width: 24px;\n height: 24px;\n fill: white;\n }\n\n .librebot-title {\n font-weight: 600;\n color: var(--lb-text);\n margin: 0;\n font-size: 16px;\n }\n\n .librebot-subtitle {\n font-size: 12px;\n color: var(--lb-text-secondary);\n margin: 0;\n }\n\n .librebot-close {\n width: 32px;\n height: 32px;\n border-radius: 8px;\n border: none;\n background: transparent;\n cursor: pointer;\n display: flex;\n align-items: center;\n justify-content: center;\n color: var(--lb-text-secondary);\n transition: background 0.2s;\n }\n\n .librebot-close:hover {\n background: var(--lb-bg-secondary);\n }\n\n .librebot-messages {\n flex: 1;\n overflow-y: auto;\n padding: 16px;\n display: flex;\n flex-direction: column;\n gap: 12px;\n }\n\n .librebot-message {\n max-width: 85%;\n padding: 10px 14px;\n border-radius: 16px;\n word-wrap: break-word;\n }\n\n .librebot-message.user {\n align-self: flex-end;\n background: var(--lb-primary);\n color: white;\n border-bottom-right-radius: 4px;\n }\n\n .librebot-message.assistant {\n align-self: flex-start;\n background: var(--lb-bg-secondary);\n color: var(--lb-text);\n border-bottom-left-radius: 4px;\n }\n\n /* Inline code */\n .librebot-inline-code {\n background: rgba(0, 0, 0, 0.3);\n padding: 2px 6px;\n border-radius: 4px;\n font-family: 'Roboto Mono', 'Fira Code', 'Consolas', monospace;\n font-size: 12px;\n color: #f0f0f0;\n }\n\n .librebot-widget.light .librebot-inline-code {\n background: rgba(0, 0, 0, 0.08);\n color: #1a1a1a;\n }\n\n /* Code blocks */\n .librebot-code-block {\n background: #0d1117;\n padding: 12px 14px;\n border-radius: 8px;\n overflow-x: auto;\n margin: 10px 0;\n border: 1px solid rgba(255, 255, 255, 0.1);\n position: relative;\n }\n\n .librebot-widget.light .librebot-code-block {\n background: #f6f8fa;\n border-color: rgba(0, 0, 0, 0.1);\n }\n\n .librebot-code-block code {\n font-family: 'Roboto Mono', 'Fira Code', 'Consolas', monospace;\n font-size: 12px;\n line-height: 1.5;\n color: #e6edf3;\n background: none;\n padding: 0;\n white-space: pre;\n display: block;\n }\n\n .librebot-widget.light .librebot-code-block code {\n color: #24292f;\n }\n\n .librebot-code-block[data-language]::before {\n content: attr(data-language);\n position: absolute;\n top: 6px;\n right: 10px;\n font-size: 10px;\n color: rgba(255, 255, 255, 0.4);\n text-transform: uppercase;\n font-family: 'Roboto Mono', monospace;\n }\n\n .librebot-widget.light .librebot-code-block[data-language]::before {\n color: rgba(0, 0, 0, 0.3);\n }\n\n /* Headers */\n .librebot-h2 {\n font-size: 16px;\n font-weight: 600;\n margin: 12px 0 8px 0;\n color: var(--lb-text);\n }\n\n .librebot-h3 {\n font-size: 14px;\n font-weight: 600;\n margin: 10px 0 6px 0;\n color: var(--lb-text);\n }\n\n .librebot-h4 {\n font-size: 13px;\n font-weight: 600;\n margin: 8px 0 4px 0;\n color: var(--lb-text);\n }\n\n /* Lists */\n .librebot-ul, .librebot-ol {\n margin: 8px 0;\n padding-left: 20px;\n }\n\n .librebot-ul {\n list-style-type: disc;\n }\n\n .librebot-ol {\n list-style-type: decimal;\n }\n\n .librebot-li, .librebot-li-ordered {\n margin: 4px 0;\n padding-left: 4px;\n line-height: 1.5;\n }\n\n /* Links */\n .librebot-link {\n color: var(--lb-primary);\n text-decoration: none;\n border-bottom: 1px solid transparent;\n transition: border-color 0.2s;\n }\n\n .librebot-link:hover {\n border-bottom-color: var(--lb-primary);\n }\n\n /* Blockquotes */\n .librebot-blockquote {\n border-left: 3px solid var(--lb-primary);\n margin: 8px 0;\n padding: 4px 12px;\n color: var(--lb-text-secondary);\n font-style: italic;\n background: rgba(0, 0, 0, 0.1);\n border-radius: 0 6px 6px 0;\n }\n\n .librebot-widget.light .librebot-blockquote {\n background: rgba(0, 0, 0, 0.04);\n }\n\n /* Horizontal rule */\n .librebot-hr {\n border: none;\n border-top: 1px solid var(--lb-border);\n margin: 12px 0;\n }\n\n /* Strong and emphasis */\n .librebot-message strong {\n font-weight: 600;\n }\n\n .librebot-message em {\n font-style: italic;\n }\n\n /* Legacy support for old code elements */\n .librebot-message code:not(.librebot-inline-code) {\n background: rgba(0, 0, 0, 0.2);\n padding: 2px 6px;\n border-radius: 4px;\n font-family: monospace;\n font-size: 13px;\n }\n\n .librebot-message pre:not(.librebot-code-block) {\n background: rgba(0, 0, 0, 0.3);\n padding: 10px;\n border-radius: 8px;\n overflow-x: auto;\n margin: 8px 0;\n }\n\n .librebot-message pre:not(.librebot-code-block) code {\n background: none;\n padding: 0;\n }\n\n .librebot-typing {\n display: flex;\n gap: 4px;\n padding: 12px 16px;\n align-self: flex-start;\n background: var(--lb-bg-secondary);\n border-radius: 16px;\n border-bottom-left-radius: 4px;\n }\n\n .librebot-typing span {\n width: 8px;\n height: 8px;\n background: var(--lb-text-secondary);\n border-radius: 50%;\n animation: librebot-bounce 1.4s infinite ease-in-out;\n }\n\n .librebot-typing span:nth-child(1) { animation-delay: 0s; }\n .librebot-typing span:nth-child(2) { animation-delay: 0.2s; }\n .librebot-typing span:nth-child(3) { animation-delay: 0.4s; }\n\n @keyframes librebot-bounce {\n 0%, 80%, 100% { transform: scale(0.8); opacity: 0.5; }\n 40% { transform: scale(1); opacity: 1; }\n }\n\n .librebot-input-area {\n padding: 12px 16px;\n border-top: 1px solid var(--lb-border);\n display: flex;\n gap: 8px;\n }\n\n .librebot-input {\n flex: 1;\n padding: 10px 14px;\n border: 1px solid var(--lb-border);\n border-radius: 24px;\n background: var(--lb-bg-secondary);\n color: var(--lb-text);\n font-size: 14px;\n outline: none;\n transition: border-color 0.2s;\n }\n\n .librebot-input:focus {\n border-color: var(--lb-primary);\n }\n\n .librebot-input::placeholder {\n color: var(--lb-text-secondary);\n }\n\n .librebot-send {\n width: 40px;\n height: 40px;\n border-radius: 50%;\n border: none;\n background: var(--lb-primary);\n cursor: pointer;\n display: flex;\n align-items: center;\n justify-content: center;\n transition: background 0.2s;\n }\n\n .librebot-send:hover {\n background: var(--lb-primary-hover);\n }\n\n .librebot-send:disabled {\n opacity: 0.5;\n cursor: not-allowed;\n }\n\n .librebot-send svg {\n width: 18px;\n height: 18px;\n fill: white;\n }\n\n .librebot-welcome {\n text-align: center;\n padding: 20px;\n color: var(--lb-text-secondary);\n }\n\n .librebot-welcome-icon {\n width: 48px;\n height: 48px;\n margin: 0 auto 12px;\n background: var(--lb-primary);\n border-radius: 12px;\n display: flex;\n align-items: center;\n justify-content: center;\n }\n\n .librebot-welcome-icon svg {\n width: 28px;\n height: 28px;\n fill: white;\n }\n\n .librebot-powered {\n text-align: center;\n padding: 8px;\n font-size: 11px;\n color: var(--lb-text-secondary);\n border-top: 1px solid var(--lb-border);\n }\n\n .librebot-powered a {\n color: var(--lb-primary);\n text-decoration: none;\n }\n\n .librebot-powered a:hover {\n text-decoration: underline;\n }\n`)(this.config.primaryColor),document.head.appendChild(n)}createWidget(){this.container=document.createElement("div"),this.container.className="librebot-widget "+("light"===this.config.theme?"light":"");const e=document.createElement("button");e.className="librebot-fab "+("bottom-left"===this.config.position?"left":""),e.innerHTML=n,e.onclick=()=>this.toggle(),this.modal=document.createElement("div"),this.modal.className="librebot-modal "+("bottom-left"===this.config.position?"left":""),this.modal.innerHTML=this.getModalHTML(),this.container.appendChild(e),this.container.appendChild(this.modal),document.body.appendChild(this.container),this.messagesContainer=this.modal.querySelector(".librebot-messages"),this.input=this.modal.querySelector(".librebot-input");const t=this.modal.querySelector(".librebot-close");t?.addEventListener("click",()=>this.close());const o=this.modal.querySelector(".librebot-send");if(o?.addEventListener("click",()=>this.sendMessage()),this.input?.addEventListener("keypress",e=>{"Enter"!==e.key||e.shiftKey||(e.preventDefault(),this.sendMessage())}),"auto"===this.config.theme){const e=window.matchMedia("(prefers-color-scheme: light)");this.updateTheme(e.matches),e.addEventListener("change",e=>this.updateTheme(e.matches))}}getModalHTML(){const e=this.config.whiteLabel?"":'<div class="librebot-powered">\n Powered by <a href="https://librebot.io" target="_blank">Libre Bot</a>\n </div>';return`\n <div class="librebot-header">\n <div class="librebot-header-content">\n <div class="librebot-avatar">${n}</div>\n <div>\n <h3 class="librebot-title">${this.config.title}</h3>\n <p class="librebot-subtitle">${this.config.subtitle}</p>\n </div>\n </div>\n <button class="librebot-close"><svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><line x1="18" y1="6" x2="6" y2="18"></line><line x1="6" y1="6" x2="18" y2="18"></line></svg></button>\n </div>\n <div class="librebot-messages"></div>\n <div class="librebot-input-area">\n <input type="text" class="librebot-input" placeholder="${this.config.placeholder}" />\n <button class="librebot-send"><svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><line x1="22" y1="2" x2="11" y2="13"></line><polygon points="22 2 15 22 11 13 2 9 22 2"></polygon></svg></button>\n </div>\n ${e}\n `}updateTheme(e){e?this.container?.classList.add("light"):this.container?.classList.remove("light")}toggle(){this.isOpen?this.close():this.open()}open(){this.isOpen=!0,this.modal?.classList.add("open"),this.input?.focus()}close(){this.isOpen=!1,this.modal?.classList.remove("open")}addMessage(e,n){const t={id:`msg-${Date.now()}`,role:e,content:n,timestamp:new Date};this.messages.push(t),this.renderMessage(t)}renderMessage(e){if(!this.messagesContainer)return;const n=document.createElement("div");n.className=`librebot-message ${e.role}`,n.innerHTML=this.formatMessage(e.content),this.messagesContainer.appendChild(n),this.scrollToBottom()}formatMessage(e){const n=e=>e.replace(/&/g,"&amp;").replace(/</g,"&lt;").replace(/>/g,"&gt;").replace(/"/g,"&quot;").replace(/'/g,"&#039;"),t=[];let o=e.replace(/```\s*(\w*)\s*\n?([\s\S]*?)```/g,(e,o,i)=>{const r=n(i.trim()),s=o?` data-language="${n(o)}"`:"";return t.push(`<pre class="librebot-code-block"${s}><code>${r}</code></pre>`),`%%CODEBLOCK${t.length-1}%%`});const i=[];return o=o.replace(/`([^`]+)`/g,(e,t)=>(i.push(`<code class="librebot-inline-code">${n(t)}</code>`),`%%INLINECODE${i.length-1}%%`)),o=n(o),o=o.replace(/^### (.+)$/gm,'<h4 class="librebot-h4">$1</h4>'),o=o.replace(/^## (.+)$/gm,'<h3 class="librebot-h3">$1</h3>'),o=o.replace(/^# (.+)$/gm,'<h2 class="librebot-h2">$1</h2>'),o=o.replace(/\*\*\*([^*]+)\*\*\*/g,"<strong><em>$1</em></strong>"),o=o.replace(/\*\*([^*]+)\*\*/g,"<strong>$1</strong>"),o=o.replace(/\*([^*]+)\*/g,"<em>$1</em>"),o=o.replace(/_([^_]+)_/g,"<em>$1</em>"),o=o.replace(/\[([^\]]+)\]\(([^)]+)\)/g,'<a href="$2" target="_blank" rel="noopener noreferrer" class="librebot-link">$1</a>'),o=o.replace(/^[\*\-] (.+)$/gm,'<li class="librebot-li">$1</li>'),o=o.replace(/(<li class="librebot-li">.*<\/li>\n?)+/g,e=>`<ul class="librebot-ul">${e}</ul>`),o=o.replace(/^\d+\. (.+)$/gm,'<li class="librebot-li-ordered">$1</li>'),o=o.replace(/(<li class="librebot-li-ordered">.*<\/li>\n?)+/g,e=>`<ol class="librebot-ol">${e}</ol>`),o=o.replace(/^---$/gm,'<hr class="librebot-hr">'),o=o.replace(/^&gt; (.+)$/gm,'<blockquote class="librebot-blockquote">$1</blockquote>'),o=o.replace(/\n/g,"<br>"),o=o.replace(/<\/(pre|ul|ol|blockquote|h[2-4])><br>/g,"</$1>"),o=o.replace(/<br><(pre|ul|ol|blockquote|h[2-4])/g,"<$1"),t.forEach((e,n)=>{o=o.replace(`%%CODEBLOCK${n}%%`,e)}),i.forEach((e,n)=>{o=o.replace(`%%INLINECODE${n}%%`,e)}),o}showTyping(){const e=document.createElement("div");return e.className="librebot-typing",e.innerHTML="<span></span><span></span><span></span>",this.messagesContainer?.appendChild(e),this.scrollToBottom(),e}scrollToBottom(){this.messagesContainer&&(this.messagesContainer.scrollTop=this.messagesContainer.scrollHeight)}async sendMessage(){if(!this.input||this.isLoading)return;const e=this.input.value.trim();if(!e)return;this.addMessage("user",e),this.input.value="",this.isLoading=!0;const n=this.showTyping();try{if(this.config.streaming)await this.callStreamingAPI(e,n);else{const t=await this.callAPI(e);n.remove(),t.error?this.addMessage("assistant",`Sorry, I encountered an error: ${t.error}`):this.addMessage("assistant",t.response)}}catch(e){n.remove(),this.addMessage("assistant","Sorry, I had trouble connecting. Please try again."),console.error("LibreBot error:",e)}finally{this.isLoading=!1}}async callStreamingAPI(e,n){const t=await fetch(`${this.config.apiUrl}/chat`,{method:"POST",headers:{"Content-Type":"application/json",Authorization:`Bearer ${this.config.apiKey}`},body:JSON.stringify({message:e,context:this.getConversationContext(),stream:!0,sessionId:this.sessionId})});if(!t.ok){n.remove();const e=await t.json().catch(()=>({error:"Request failed"}));return void this.addMessage("assistant",`Sorry, I encountered an error: ${e.error||"Request failed"}`)}n.remove();const o=document.createElement("div");o.className="librebot-message assistant",this.messagesContainer?.appendChild(o);const i=t.body?.getReader();if(!i)return void this.addMessage("assistant","Sorry, streaming is not supported.");const r=new TextDecoder;let s="";try{for(;;){const{done:e,value:n}=await i.read();if(e)break;const t=r.decode(n,{stream:!0}).split("\n").filter(e=>""!==e.trim());for(const e of t)if(e.startsWith("data: ")){const n=e.slice(6);if("[DONE]"===n)continue;try{const e=JSON.parse(n);e.content&&(s+=e.content,o.innerHTML=this.formatMessage(s),this.scrollToBottom()),e.sessionId&&this.saveSession(e.sessionId)}catch{}}}}catch(e){console.error("Stream reading error:",e)}this.messages.push({id:`msg-${Date.now()}`,role:"assistant",content:s,timestamp:new Date})}async callAPI(e){const n=await fetch(`${this.config.apiUrl}/chat`,{method:"POST",headers:{"Content-Type":"application/json",Authorization:`Bearer ${this.config.apiKey}`},body:JSON.stringify({message:e,context:this.getConversationContext(),sessionId:this.sessionId})});if(!n.ok){return{response:"",error:(await n.json().catch(()=>({error:"Request failed"}))).error||"Request failed"}}const t=await n.json();return t.sessionId&&this.saveSession(t.sessionId),t}getConversationContext(){return this.messages.slice(-10).map(e=>({role:e.role,content:e.content}))}destroy(){this.container?.remove(),document.getElementById("librebot-styles")?.remove()}clearSession(){try{this.sessionId=null,this.messages=[],localStorage.removeItem(this.getSessionKey()),this.messagesContainer&&(this.messagesContainer.innerHTML=""),this.config.welcomeMessage&&this.addMessage("assistant",this.config.welcomeMessage)}catch{}}}return function(){const e=document.currentScript||document.querySelector('script[data-key][src*="librebot"]');if(!e)return void console.warn("LibreBot: Could not find script tag");const n={apiKey:e.dataset.key||e.dataset.apiKey||"",apiUrl:e.dataset.apiUrl||"https://api.librebot.io",position:e.dataset.position||"bottom-right",theme:e.dataset.theme||"dark",primaryColor:e.dataset.color||"#14b8a6",title:e.dataset.title||"Libre Bot",subtitle:e.dataset.subtitle||"AI Documentation Assistant",placeholder:e.dataset.placeholder||"Ask a question...",welcomeMessage:e.dataset.welcome||"Hi! I can help you find answers in the documentation. What would you like to know?",streaming:"false"!==e.dataset.streaming};n.apiKey?"loading"===document.readyState?document.addEventListener("DOMContentLoaded",()=>{window.LibreBot=new t(n)}):window.LibreBot=new t(n):console.error("LibreBot: Missing data-key attribute")}(),e.LibreBotWidget=t,e}({});
2
2
  //# sourceMappingURL=librebot.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"librebot.js","sources":["../src/styles.ts","../src/icons.ts","../src/widget.ts","../src/embed.ts"],"sourcesContent":["export const getStyles = (primaryColor: string = '#14b8a6') => `\n .librebot-widget {\n --lb-primary: ${primaryColor};\n --lb-primary-hover: color-mix(in srgb, ${primaryColor} 85%, white);\n --lb-bg: #0f0f0f;\n --lb-bg-secondary: #1a1a1a;\n --lb-text: #ffffff;\n --lb-text-secondary: #9ca3af;\n --lb-border: #2a2a2a;\n font-family: 'Roboto Mono', -apple-system, BlinkMacSystemFont, 'Segoe UI', monospace;\n font-size: 14px;\n line-height: 1.5;\n }\n\n .librebot-widget.light {\n --lb-bg: #ffffff;\n --lb-bg-secondary: #f5f5f5;\n --lb-text: #1a1a1a;\n --lb-text-secondary: #666666;\n --lb-border: #e0e0e0;\n }\n\n .librebot-fab {\n position: fixed;\n bottom: 20px;\n right: 20px;\n width: 56px;\n height: 56px;\n border-radius: 50%;\n background: var(--lb-primary);\n border: none;\n cursor: pointer;\n box-shadow: 0 4px 12px rgba(0, 0, 0, 0.3);\n display: flex;\n align-items: center;\n justify-content: center;\n transition: transform 0.2s, box-shadow 0.2s;\n z-index: 999998;\n }\n\n .librebot-fab:hover {\n transform: scale(1.05);\n box-shadow: 0 6px 16px rgba(0, 0, 0, 0.4);\n }\n\n .librebot-fab svg {\n width: 24px;\n height: 24px;\n fill: white;\n }\n\n .librebot-fab.left {\n right: auto;\n left: 20px;\n }\n\n .librebot-modal {\n position: fixed;\n bottom: 90px;\n right: 20px;\n width: 380px;\n max-width: calc(100vw - 40px);\n height: 520px;\n max-height: calc(100vh - 120px);\n background: var(--lb-bg);\n border: 1px solid var(--lb-border);\n border-radius: 16px;\n box-shadow: 0 8px 32px rgba(0, 0, 0, 0.3);\n display: flex;\n flex-direction: column;\n overflow: hidden;\n z-index: 999999;\n opacity: 0;\n transform: translateY(20px) scale(0.95);\n transition: opacity 0.2s, transform 0.2s;\n pointer-events: none;\n }\n\n .librebot-modal.open {\n opacity: 1;\n transform: translateY(0) scale(1);\n pointer-events: auto;\n }\n\n .librebot-modal.left {\n right: auto;\n left: 20px;\n }\n\n .librebot-header {\n padding: 16px;\n border-bottom: 1px solid var(--lb-border);\n display: flex;\n align-items: center;\n justify-content: space-between;\n }\n\n .librebot-header-content {\n display: flex;\n align-items: center;\n gap: 12px;\n }\n\n .librebot-avatar {\n width: 40px;\n height: 40px;\n border-radius: 10px;\n background: var(--lb-primary);\n display: flex;\n align-items: center;\n justify-content: center;\n }\n\n .librebot-avatar svg {\n width: 24px;\n height: 24px;\n fill: white;\n }\n\n .librebot-title {\n font-weight: 600;\n color: var(--lb-text);\n margin: 0;\n font-size: 16px;\n }\n\n .librebot-subtitle {\n font-size: 12px;\n color: var(--lb-text-secondary);\n margin: 0;\n }\n\n .librebot-close {\n width: 32px;\n height: 32px;\n border-radius: 8px;\n border: none;\n background: transparent;\n cursor: pointer;\n display: flex;\n align-items: center;\n justify-content: center;\n color: var(--lb-text-secondary);\n transition: background 0.2s;\n }\n\n .librebot-close:hover {\n background: var(--lb-bg-secondary);\n }\n\n .librebot-messages {\n flex: 1;\n overflow-y: auto;\n padding: 16px;\n display: flex;\n flex-direction: column;\n gap: 12px;\n }\n\n .librebot-message {\n max-width: 85%;\n padding: 10px 14px;\n border-radius: 16px;\n word-wrap: break-word;\n }\n\n .librebot-message.user {\n align-self: flex-end;\n background: var(--lb-primary);\n color: white;\n border-bottom-right-radius: 4px;\n }\n\n .librebot-message.assistant {\n align-self: flex-start;\n background: var(--lb-bg-secondary);\n color: var(--lb-text);\n border-bottom-left-radius: 4px;\n }\n\n /* Inline code */\n .librebot-inline-code {\n background: rgba(0, 0, 0, 0.3);\n padding: 2px 6px;\n border-radius: 4px;\n font-family: 'Roboto Mono', 'Fira Code', 'Consolas', monospace;\n font-size: 12px;\n color: #f0f0f0;\n }\n\n .librebot-widget.light .librebot-inline-code {\n background: rgba(0, 0, 0, 0.08);\n color: #1a1a1a;\n }\n\n /* Code blocks */\n .librebot-code-block {\n background: #0d1117;\n padding: 12px 14px;\n border-radius: 8px;\n overflow-x: auto;\n margin: 10px 0;\n border: 1px solid rgba(255, 255, 255, 0.1);\n position: relative;\n }\n\n .librebot-widget.light .librebot-code-block {\n background: #f6f8fa;\n border-color: rgba(0, 0, 0, 0.1);\n }\n\n .librebot-code-block code {\n font-family: 'Roboto Mono', 'Fira Code', 'Consolas', monospace;\n font-size: 12px;\n line-height: 1.5;\n color: #e6edf3;\n background: none;\n padding: 0;\n white-space: pre;\n display: block;\n }\n\n .librebot-widget.light .librebot-code-block code {\n color: #24292f;\n }\n\n .librebot-code-block[data-language]::before {\n content: attr(data-language);\n position: absolute;\n top: 6px;\n right: 10px;\n font-size: 10px;\n color: rgba(255, 255, 255, 0.4);\n text-transform: uppercase;\n font-family: 'Roboto Mono', monospace;\n }\n\n .librebot-widget.light .librebot-code-block[data-language]::before {\n color: rgba(0, 0, 0, 0.3);\n }\n\n /* Headers */\n .librebot-h2 {\n font-size: 16px;\n font-weight: 600;\n margin: 12px 0 8px 0;\n color: var(--lb-text);\n }\n\n .librebot-h3 {\n font-size: 14px;\n font-weight: 600;\n margin: 10px 0 6px 0;\n color: var(--lb-text);\n }\n\n .librebot-h4 {\n font-size: 13px;\n font-weight: 600;\n margin: 8px 0 4px 0;\n color: var(--lb-text);\n }\n\n /* Lists */\n .librebot-ul, .librebot-ol {\n margin: 8px 0;\n padding-left: 20px;\n }\n\n .librebot-ul {\n list-style-type: disc;\n }\n\n .librebot-ol {\n list-style-type: decimal;\n }\n\n .librebot-li, .librebot-li-ordered {\n margin: 4px 0;\n padding-left: 4px;\n line-height: 1.5;\n }\n\n /* Links */\n .librebot-link {\n color: var(--lb-primary);\n text-decoration: none;\n border-bottom: 1px solid transparent;\n transition: border-color 0.2s;\n }\n\n .librebot-link:hover {\n border-bottom-color: var(--lb-primary);\n }\n\n /* Blockquotes */\n .librebot-blockquote {\n border-left: 3px solid var(--lb-primary);\n margin: 8px 0;\n padding: 4px 12px;\n color: var(--lb-text-secondary);\n font-style: italic;\n background: rgba(0, 0, 0, 0.1);\n border-radius: 0 6px 6px 0;\n }\n\n .librebot-widget.light .librebot-blockquote {\n background: rgba(0, 0, 0, 0.04);\n }\n\n /* Horizontal rule */\n .librebot-hr {\n border: none;\n border-top: 1px solid var(--lb-border);\n margin: 12px 0;\n }\n\n /* Strong and emphasis */\n .librebot-message strong {\n font-weight: 600;\n }\n\n .librebot-message em {\n font-style: italic;\n }\n\n /* Legacy support for old code elements */\n .librebot-message code:not(.librebot-inline-code) {\n background: rgba(0, 0, 0, 0.2);\n padding: 2px 6px;\n border-radius: 4px;\n font-family: monospace;\n font-size: 13px;\n }\n\n .librebot-message pre:not(.librebot-code-block) {\n background: rgba(0, 0, 0, 0.3);\n padding: 10px;\n border-radius: 8px;\n overflow-x: auto;\n margin: 8px 0;\n }\n\n .librebot-message pre:not(.librebot-code-block) code {\n background: none;\n padding: 0;\n }\n\n .librebot-typing {\n display: flex;\n gap: 4px;\n padding: 12px 16px;\n align-self: flex-start;\n background: var(--lb-bg-secondary);\n border-radius: 16px;\n border-bottom-left-radius: 4px;\n }\n\n .librebot-typing span {\n width: 8px;\n height: 8px;\n background: var(--lb-text-secondary);\n border-radius: 50%;\n animation: librebot-bounce 1.4s infinite ease-in-out;\n }\n\n .librebot-typing span:nth-child(1) { animation-delay: 0s; }\n .librebot-typing span:nth-child(2) { animation-delay: 0.2s; }\n .librebot-typing span:nth-child(3) { animation-delay: 0.4s; }\n\n @keyframes librebot-bounce {\n 0%, 80%, 100% { transform: scale(0.8); opacity: 0.5; }\n 40% { transform: scale(1); opacity: 1; }\n }\n\n .librebot-input-area {\n padding: 12px 16px;\n border-top: 1px solid var(--lb-border);\n display: flex;\n gap: 8px;\n }\n\n .librebot-input {\n flex: 1;\n padding: 10px 14px;\n border: 1px solid var(--lb-border);\n border-radius: 24px;\n background: var(--lb-bg-secondary);\n color: var(--lb-text);\n font-size: 14px;\n outline: none;\n transition: border-color 0.2s;\n }\n\n .librebot-input:focus {\n border-color: var(--lb-primary);\n }\n\n .librebot-input::placeholder {\n color: var(--lb-text-secondary);\n }\n\n .librebot-send {\n width: 40px;\n height: 40px;\n border-radius: 50%;\n border: none;\n background: var(--lb-primary);\n cursor: pointer;\n display: flex;\n align-items: center;\n justify-content: center;\n transition: background 0.2s;\n }\n\n .librebot-send:hover {\n background: var(--lb-primary-hover);\n }\n\n .librebot-send:disabled {\n opacity: 0.5;\n cursor: not-allowed;\n }\n\n .librebot-send svg {\n width: 18px;\n height: 18px;\n fill: white;\n }\n\n .librebot-welcome {\n text-align: center;\n padding: 20px;\n color: var(--lb-text-secondary);\n }\n\n .librebot-welcome-icon {\n width: 48px;\n height: 48px;\n margin: 0 auto 12px;\n background: var(--lb-primary);\n border-radius: 12px;\n display: flex;\n align-items: center;\n justify-content: center;\n }\n\n .librebot-welcome-icon svg {\n width: 28px;\n height: 28px;\n fill: white;\n }\n\n .librebot-powered {\n text-align: center;\n padding: 8px;\n font-size: 11px;\n color: var(--lb-text-secondary);\n border-top: 1px solid var(--lb-border);\n }\n\n .librebot-powered a {\n color: var(--lb-primary);\n text-decoration: none;\n }\n\n .librebot-powered a:hover {\n text-decoration: underline;\n }\n`;\n","export const chatIcon = `<svg viewBox=\"0 0 24 24\" fill=\"none\" stroke=\"currentColor\" stroke-width=\"2\" stroke-linecap=\"round\" stroke-linejoin=\"round\"><path d=\"M21 15a2 2 0 0 1-2 2H7l-4 4V5a2 2 0 0 1 2-2h14a2 2 0 0 1 2 2z\"></path></svg>`;\n\nexport const closeIcon = `<svg viewBox=\"0 0 24 24\" fill=\"none\" stroke=\"currentColor\" stroke-width=\"2\" stroke-linecap=\"round\" stroke-linejoin=\"round\"><line x1=\"18\" y1=\"6\" x2=\"6\" y2=\"18\"></line><line x1=\"6\" y1=\"6\" x2=\"18\" y2=\"18\"></line></svg>`;\n\nexport const sendIcon = `<svg viewBox=\"0 0 24 24\" fill=\"none\" stroke=\"currentColor\" stroke-width=\"2\" stroke-linecap=\"round\" stroke-linejoin=\"round\"><line x1=\"22\" y1=\"2\" x2=\"11\" y2=\"13\"></line><polygon points=\"22 2 15 22 11 13 2 9 22 2\"></polygon></svg>`;\n\nexport const botIcon = `<svg viewBox=\"0 0 24 24\" fill=\"currentColor\"><path d=\"M12 2C6.48 2 2 6.48 2 12s4.48 10 10 10 10-4.48 10-10S17.52 2 12 2zm-2 15l-5-5 1.41-1.41L10 14.17l7.59-7.59L19 8l-9 9z\"/></svg>`;\n","import { LibreBotConfig, Message, ChatResponse } from './types';\nimport { getStyles } from './styles';\nimport { chatIcon, closeIcon, sendIcon } from './icons';\n\nexport class LibreBotWidget {\n private config!: Required<LibreBotConfig>;\n private container: HTMLDivElement | null = null;\n private modal: HTMLDivElement | null = null;\n private messagesContainer: HTMLDivElement | null = null;\n private input: HTMLInputElement | null = null;\n private isOpen = false;\n private messages: Message[] = [];\n private isLoading = false;\n\n private defaultConfig: Omit<Required<LibreBotConfig>, 'apiKey'> = {\n apiUrl: 'https://librebot.io/api',\n position: 'bottom-right',\n theme: 'dark',\n primaryColor: '#14b8a6',\n title: 'Libre Bot',\n subtitle: 'AI Documentation Assistant',\n placeholder: 'Ask a question...',\n welcomeMessage: 'Hi! I can help you find answers in the documentation. What would you like to know?',\n streaming: true,\n whiteLabel: false,\n autoLoadConfig: true,\n };\n\n constructor(config: LibreBotConfig) {\n if (!config.apiKey) {\n console.error('LibreBot: API key is required');\n return;\n }\n\n this.config = { ...this.defaultConfig, ...config } as Required<LibreBotConfig>;\n\n // Auto-load config from server if enabled and no custom settings provided\n if (this.config.autoLoadConfig) {\n this.loadRemoteConfig().then(() => this.init());\n } else {\n this.init();\n }\n }\n\n private async loadRemoteConfig(): Promise<void> {\n try {\n const response = await fetch(`${this.config.apiUrl}/widget-config?key=${this.config.apiKey}`);\n if (response.ok) {\n const remoteConfig = await response.json();\n // Merge remote config with local config (local overrides remote)\n this.config = {\n ...this.defaultConfig,\n ...remoteConfig,\n ...this.getProvidedConfig(),\n apiKey: this.config.apiKey,\n apiUrl: this.config.apiUrl,\n autoLoadConfig: this.config.autoLoadConfig,\n } as Required<LibreBotConfig>;\n }\n } catch (error) {\n console.warn('LibreBot: Could not load remote config, using defaults', error);\n }\n }\n\n private getProvidedConfig(): Partial<LibreBotConfig> {\n // Return only the config options that were explicitly provided (not default values)\n const provided: Partial<LibreBotConfig> = {};\n const userConfig = this.config;\n const defaults = this.defaultConfig;\n\n if (userConfig.position !== defaults.position) provided.position = userConfig.position;\n if (userConfig.theme !== defaults.theme) provided.theme = userConfig.theme;\n if (userConfig.primaryColor !== defaults.primaryColor) provided.primaryColor = userConfig.primaryColor;\n if (userConfig.title !== defaults.title) provided.title = userConfig.title;\n if (userConfig.subtitle !== defaults.subtitle) provided.subtitle = userConfig.subtitle;\n if (userConfig.placeholder !== defaults.placeholder) provided.placeholder = userConfig.placeholder;\n if (userConfig.welcomeMessage !== defaults.welcomeMessage) provided.welcomeMessage = userConfig.welcomeMessage;\n if (userConfig.streaming !== defaults.streaming) provided.streaming = userConfig.streaming;\n if (userConfig.whiteLabel !== defaults.whiteLabel) provided.whiteLabel = userConfig.whiteLabel;\n\n return provided;\n }\n\n private init(): void {\n // Inject styles\n this.injectStyles();\n\n // Create widget container\n this.createWidget();\n\n // Add welcome message\n if (this.config.welcomeMessage) {\n this.addMessage('assistant', this.config.welcomeMessage);\n }\n }\n\n private injectStyles(): void {\n const styleId = 'librebot-styles';\n if (document.getElementById(styleId)) return;\n\n const style = document.createElement('style');\n style.id = styleId;\n style.textContent = getStyles(this.config.primaryColor);\n document.head.appendChild(style);\n }\n\n private createWidget(): void {\n // Create container\n this.container = document.createElement('div');\n this.container.className = `librebot-widget ${this.config.theme === 'light' ? 'light' : ''}`;\n\n // Create FAB button\n const fab = document.createElement('button');\n fab.className = `librebot-fab ${this.config.position === 'bottom-left' ? 'left' : ''}`;\n fab.innerHTML = chatIcon;\n fab.onclick = () => this.toggle();\n\n // Create modal\n this.modal = document.createElement('div');\n this.modal.className = `librebot-modal ${this.config.position === 'bottom-left' ? 'left' : ''}`;\n this.modal.innerHTML = this.getModalHTML();\n\n // Add to container\n this.container.appendChild(fab);\n this.container.appendChild(this.modal);\n document.body.appendChild(this.container);\n\n // Get references\n this.messagesContainer = this.modal.querySelector('.librebot-messages');\n this.input = this.modal.querySelector('.librebot-input');\n\n // Add event listeners\n const closeBtn = this.modal.querySelector('.librebot-close');\n closeBtn?.addEventListener('click', () => this.close());\n\n const sendBtn = this.modal.querySelector('.librebot-send');\n sendBtn?.addEventListener('click', () => this.sendMessage());\n\n this.input?.addEventListener('keypress', (e) => {\n if (e.key === 'Enter' && !e.shiftKey) {\n e.preventDefault();\n this.sendMessage();\n }\n });\n\n // Auto theme detection\n if (this.config.theme === 'auto') {\n const mediaQuery = window.matchMedia('(prefers-color-scheme: light)');\n this.updateTheme(mediaQuery.matches);\n mediaQuery.addEventListener('change', (e) => this.updateTheme(e.matches));\n }\n }\n\n private getModalHTML(): string {\n const poweredByHtml = this.config.whiteLabel\n ? ''\n : `<div class=\"librebot-powered\">\n Powered by <a href=\"https://librebot.io\" target=\"_blank\">Libre Bot</a>\n </div>`;\n\n return `\n <div class=\"librebot-header\">\n <div class=\"librebot-header-content\">\n <div class=\"librebot-avatar\">${chatIcon}</div>\n <div>\n <h3 class=\"librebot-title\">${this.config.title}</h3>\n <p class=\"librebot-subtitle\">${this.config.subtitle}</p>\n </div>\n </div>\n <button class=\"librebot-close\">${closeIcon}</button>\n </div>\n <div class=\"librebot-messages\"></div>\n <div class=\"librebot-input-area\">\n <input type=\"text\" class=\"librebot-input\" placeholder=\"${this.config.placeholder}\" />\n <button class=\"librebot-send\">${sendIcon}</button>\n </div>\n ${poweredByHtml}\n `;\n }\n\n private updateTheme(isLight: boolean): void {\n if (isLight) {\n this.container?.classList.add('light');\n } else {\n this.container?.classList.remove('light');\n }\n }\n\n public toggle(): void {\n this.isOpen ? this.close() : this.open();\n }\n\n public open(): void {\n this.isOpen = true;\n this.modal?.classList.add('open');\n this.input?.focus();\n }\n\n public close(): void {\n this.isOpen = false;\n this.modal?.classList.remove('open');\n }\n\n private addMessage(role: 'user' | 'assistant', content: string): void {\n const message: Message = {\n id: `msg-${Date.now()}`,\n role,\n content,\n timestamp: new Date(),\n };\n\n this.messages.push(message);\n this.renderMessage(message);\n }\n\n private renderMessage(message: Message): void {\n if (!this.messagesContainer) return;\n\n const el = document.createElement('div');\n el.className = `librebot-message ${message.role}`;\n el.innerHTML = this.formatMessage(message.content);\n\n this.messagesContainer.appendChild(el);\n this.scrollToBottom();\n }\n\n private formatMessage(content: string): string {\n // Escape HTML to prevent XSS\n const escapeHtml = (text: string): string => {\n return text\n .replace(/&/g, '&amp;')\n .replace(/</g, '&lt;')\n .replace(/>/g, '&gt;')\n .replace(/\"/g, '&quot;')\n .replace(/'/g, '&#039;');\n };\n\n // First, extract code blocks to protect them from other formatting\n // Regex handles optional space/newline after ``` and optional language identifier\n const codeBlocks: string[] = [];\n let processed = content.replace(/```\\s*(\\w*)\\s*\\n?([\\s\\S]*?)```/g, (_, lang, code) => {\n const escaped = escapeHtml(code.trim());\n const langClass = lang ? ` data-language=\"${escapeHtml(lang)}\"` : '';\n codeBlocks.push(`<pre class=\"librebot-code-block\"${langClass}><code>${escaped}</code></pre>`);\n return `%%CODEBLOCK${codeBlocks.length - 1}%%`;\n });\n\n // Extract inline code\n const inlineCodes: string[] = [];\n processed = processed.replace(/`([^`]+)`/g, (_, code) => {\n inlineCodes.push(`<code class=\"librebot-inline-code\">${escapeHtml(code)}</code>`);\n return `%%INLINECODE${inlineCodes.length - 1}%%`;\n });\n\n // Now escape remaining HTML\n processed = escapeHtml(processed);\n\n // Headers (## and ###)\n processed = processed.replace(/^### (.+)$/gm, '<h4 class=\"librebot-h4\">$1</h4>');\n processed = processed.replace(/^## (.+)$/gm, '<h3 class=\"librebot-h3\">$1</h3>');\n processed = processed.replace(/^# (.+)$/gm, '<h2 class=\"librebot-h2\">$1</h2>');\n\n // Bold and italic\n processed = processed.replace(/\\*\\*\\*([^*]+)\\*\\*\\*/g, '<strong><em>$1</em></strong>');\n processed = processed.replace(/\\*\\*([^*]+)\\*\\*/g, '<strong>$1</strong>');\n processed = processed.replace(/\\*([^*]+)\\*/g, '<em>$1</em>');\n processed = processed.replace(/_([^_]+)_/g, '<em>$1</em>');\n\n // Links [text](url)\n processed = processed.replace(/\\[([^\\]]+)\\]\\(([^)]+)\\)/g, '<a href=\"$2\" target=\"_blank\" rel=\"noopener noreferrer\" class=\"librebot-link\">$1</a>');\n\n // Unordered lists\n processed = processed.replace(/^[\\*\\-] (.+)$/gm, '<li class=\"librebot-li\">$1</li>');\n processed = processed.replace(/(<li class=\"librebot-li\">.*<\\/li>\\n?)+/g, (match) => {\n return `<ul class=\"librebot-ul\">${match}</ul>`;\n });\n\n // Ordered lists\n processed = processed.replace(/^\\d+\\. (.+)$/gm, '<li class=\"librebot-li-ordered\">$1</li>');\n processed = processed.replace(/(<li class=\"librebot-li-ordered\">.*<\\/li>\\n?)+/g, (match) => {\n return `<ol class=\"librebot-ol\">${match}</ol>`;\n });\n\n // Horizontal rule\n processed = processed.replace(/^---$/gm, '<hr class=\"librebot-hr\">');\n\n // Blockquotes\n processed = processed.replace(/^&gt; (.+)$/gm, '<blockquote class=\"librebot-blockquote\">$1</blockquote>');\n\n // Convert newlines to <br> (but not inside lists/blockquotes)\n processed = processed.replace(/\\n/g, '<br>');\n\n // Clean up extra <br> after block elements\n processed = processed.replace(/<\\/(pre|ul|ol|blockquote|h[2-4])><br>/g, '</$1>');\n processed = processed.replace(/<br><(pre|ul|ol|blockquote|h[2-4])/g, '<$1');\n\n // Restore code blocks\n codeBlocks.forEach((block, i) => {\n processed = processed.replace(`%%CODEBLOCK${i}%%`, block);\n });\n\n // Restore inline code\n inlineCodes.forEach((code, i) => {\n processed = processed.replace(`%%INLINECODE${i}%%`, code);\n });\n\n return processed;\n }\n\n private showTyping(): HTMLDivElement {\n const typing = document.createElement('div');\n typing.className = 'librebot-typing';\n typing.innerHTML = '<span></span><span></span><span></span>';\n this.messagesContainer?.appendChild(typing);\n this.scrollToBottom();\n return typing;\n }\n\n private scrollToBottom(): void {\n if (this.messagesContainer) {\n this.messagesContainer.scrollTop = this.messagesContainer.scrollHeight;\n }\n }\n\n private async sendMessage(): Promise<void> {\n if (!this.input || this.isLoading) return;\n\n const content = this.input.value.trim();\n if (!content) return;\n\n // Add user message\n this.addMessage('user', content);\n this.input.value = '';\n\n // Show typing indicator\n this.isLoading = true;\n const typing = this.showTyping();\n\n try {\n if (this.config.streaming) {\n await this.callStreamingAPI(content, typing);\n } else {\n const response = await this.callAPI(content);\n typing.remove();\n\n if (response.error) {\n this.addMessage('assistant', `Sorry, I encountered an error: ${response.error}`);\n } else {\n this.addMessage('assistant', response.response);\n }\n }\n } catch (error) {\n typing.remove();\n this.addMessage('assistant', 'Sorry, I had trouble connecting. Please try again.');\n console.error('LibreBot error:', error);\n } finally {\n this.isLoading = false;\n }\n }\n\n private async callStreamingAPI(message: string, typing: HTMLDivElement): Promise<void> {\n const response = await fetch(`${this.config.apiUrl}/chat`, {\n method: 'POST',\n headers: {\n 'Content-Type': 'application/json',\n Authorization: `Bearer ${this.config.apiKey}`,\n },\n body: JSON.stringify({\n message,\n context: this.getConversationContext(),\n stream: true,\n }),\n });\n\n if (!response.ok) {\n typing.remove();\n const error = await response.json().catch(() => ({ error: 'Request failed' }));\n this.addMessage('assistant', `Sorry, I encountered an error: ${error.error || 'Request failed'}`);\n return;\n }\n\n // Remove typing indicator and create streaming message element\n typing.remove();\n const messageEl = document.createElement('div');\n messageEl.className = 'librebot-message assistant';\n this.messagesContainer?.appendChild(messageEl);\n\n const reader = response.body?.getReader();\n if (!reader) {\n this.addMessage('assistant', 'Sorry, streaming is not supported.');\n return;\n }\n\n const decoder = new TextDecoder();\n let fullContent = '';\n\n try {\n while (true) {\n const { done, value } = await reader.read();\n if (done) break;\n\n const chunk = decoder.decode(value, { stream: true });\n const lines = chunk.split('\\n').filter((line) => line.trim() !== '');\n\n for (const line of lines) {\n if (line.startsWith('data: ')) {\n const data = line.slice(6);\n if (data === '[DONE]') continue;\n\n try {\n const parsed = JSON.parse(data);\n if (parsed.content) {\n fullContent += parsed.content;\n messageEl.innerHTML = this.formatMessage(fullContent);\n this.scrollToBottom();\n }\n } catch {\n // Skip malformed JSON\n }\n }\n }\n }\n } catch (error) {\n console.error('Stream reading error:', error);\n }\n\n // Add to messages array\n this.messages.push({\n id: `msg-${Date.now()}`,\n role: 'assistant',\n content: fullContent,\n timestamp: new Date(),\n });\n }\n\n private async callAPI(message: string): Promise<ChatResponse> {\n const response = await fetch(`${this.config.apiUrl}/chat`, {\n method: 'POST',\n headers: {\n 'Content-Type': 'application/json',\n Authorization: `Bearer ${this.config.apiKey}`,\n },\n body: JSON.stringify({\n message,\n context: this.getConversationContext(),\n }),\n });\n\n if (!response.ok) {\n const error = await response.json().catch(() => ({ error: 'Request failed' }));\n return { response: '', error: error.error || 'Request failed' };\n }\n\n return response.json();\n }\n\n private getConversationContext(): Array<{ role: string; content: string }> {\n // Get last 10 messages for context\n return this.messages.slice(-10).map((m) => ({\n role: m.role,\n content: m.content,\n }));\n }\n\n public destroy(): void {\n this.container?.remove();\n document.getElementById('librebot-styles')?.remove();\n }\n}\n","import { LibreBotWidget } from './widget';\nimport { LibreBotConfig } from './types';\n\n// Auto-initialize from script tag\n(function () {\n // Find the script tag - document.currentScript may be null with defer\n const script = document.currentScript as HTMLScriptElement\n || document.querySelector('script[data-key][src*=\"librebot\"]') as HTMLScriptElement;\n\n if (!script) {\n console.warn('LibreBot: Could not find script tag');\n return;\n }\n\n // Get config from data attributes\n const config: LibreBotConfig = {\n apiKey: script.dataset.key || script.dataset.apiKey || '',\n apiUrl: script.dataset.apiUrl || 'https://api.librebot.io',\n position: (script.dataset.position as 'bottom-right' | 'bottom-left') || 'bottom-right',\n theme: (script.dataset.theme as 'light' | 'dark' | 'auto') || 'dark',\n primaryColor: script.dataset.color || '#14b8a6',\n title: script.dataset.title || 'Libre Bot',\n subtitle: script.dataset.subtitle || 'AI Documentation Assistant',\n placeholder: script.dataset.placeholder || 'Ask a question...',\n welcomeMessage: script.dataset.welcome || 'Hi! I can help you find answers in the documentation. What would you like to know?',\n streaming: script.dataset.streaming !== 'false', // default true\n };\n\n if (!config.apiKey) {\n console.error('LibreBot: Missing data-key attribute');\n return;\n }\n\n // Initialize when DOM is ready\n if (document.readyState === 'loading') {\n document.addEventListener('DOMContentLoaded', () => {\n (window as any).LibreBot = new LibreBotWidget(config);\n });\n } else {\n (window as any).LibreBot = new LibreBotWidget(config);\n }\n})();\n\n// Export for manual initialization\nexport { LibreBotWidget, LibreBotConfig };\n"],"names":["chatIcon","LibreBotWidget","constructor","config","this","container","modal","messagesContainer","input","isOpen","messages","isLoading","defaultConfig","apiUrl","position","theme","primaryColor","title","subtitle","placeholder","welcomeMessage","streaming","whiteLabel","autoLoadConfig","apiKey","loadRemoteConfig","then","init","console","error","response","fetch","ok","remoteConfig","json","getProvidedConfig","warn","provided","userConfig","defaults","injectStyles","createWidget","addMessage","styleId","document","getElementById","style","createElement","id","textContent","getStyles","head","appendChild","className","fab","innerHTML","onclick","toggle","getModalHTML","body","querySelector","closeBtn","addEventListener","close","sendBtn","sendMessage","e","key","shiftKey","preventDefault","mediaQuery","window","matchMedia","updateTheme","matches","poweredByHtml","isLight","classList","add","remove","open","focus","role","content","message","Date","now","timestamp","push","renderMessage","el","formatMessage","scrollToBottom","escapeHtml","text","replace","codeBlocks","processed","_","lang","code","escaped","trim","langClass","length","inlineCodes","match","forEach","block","i","showTyping","typing","scrollTop","scrollHeight","value","callStreamingAPI","callAPI","method","headers","Authorization","JSON","stringify","context","getConversationContext","stream","catch","messageEl","reader","getReader","decoder","TextDecoder","fullContent","done","read","lines","decode","split","filter","line","startsWith","data","slice","parsed","parse","map","m","destroy","script","currentScript","dataset","color","welcome","readyState","LibreBot"],"mappings":"sCAAO,MCAMA,EAAW,yNCIXC,EAwBX,WAAAC,CAAYC,GAtBJC,KAAAC,UAAmC,KACnCD,KAAAE,MAA+B,KAC/BF,KAAAG,kBAA2C,KAC3CH,KAAAI,MAAiC,KACjCJ,KAAAK,QAAS,EACTL,KAAAM,SAAsB,GACtBN,KAAAO,WAAY,EAEZP,KAAAQ,cAA0D,CAChEC,OAAQ,0BACRC,SAAU,eACVC,MAAO,OACPC,aAAc,UACdC,MAAO,YACPC,SAAU,6BACVC,YAAa,oBACbC,eAAgB,qFAChBC,WAAW,EACXC,YAAY,EACZC,gBAAgB,GAIXpB,EAAOqB,QAKZpB,KAAKD,OAAS,IAAKC,KAAKQ,iBAAkBT,GAGtCC,KAAKD,OAAOoB,eACdnB,KAAKqB,mBAAmBC,KAAK,IAAMtB,KAAKuB,QAExCvB,KAAKuB,QAVLC,QAAQC,MAAM,gCAYlB,CAEQ,sBAAMJ,GACZ,IACE,MAAMK,QAAiBC,MAAM,GAAG3B,KAAKD,OAAOU,4BAA4BT,KAAKD,OAAOqB,UACpF,GAAIM,EAASE,GAAI,CACf,MAAMC,QAAqBH,EAASI,OAEpC9B,KAAKD,OAAS,IACTC,KAAKQ,iBACLqB,KACA7B,KAAK+B,oBACRX,OAAQpB,KAAKD,OAAOqB,OACpBX,OAAQT,KAAKD,OAAOU,OACpBU,eAAgBnB,KAAKD,OAAOoB,eAEhC,CACF,CAAE,MAAOM,GACPD,QAAQQ,KAAK,yDAA0DP,EACzE,CACF,CAEQ,iBAAAM,GAEN,MAAME,EAAoC,CAAA,EACpCC,EAAalC,KAAKD,OAClBoC,EAAWnC,KAAKQ,cAYtB,OAVI0B,EAAWxB,WAAayB,EAASzB,WAAUuB,EAASvB,SAAWwB,EAAWxB,UAC1EwB,EAAWvB,QAAUwB,EAASxB,QAAOsB,EAAStB,MAAQuB,EAAWvB,OACjEuB,EAAWtB,eAAiBuB,EAASvB,eAAcqB,EAASrB,aAAesB,EAAWtB,cACtFsB,EAAWrB,QAAUsB,EAAStB,QAAOoB,EAASpB,MAAQqB,EAAWrB,OACjEqB,EAAWpB,WAAaqB,EAASrB,WAAUmB,EAASnB,SAAWoB,EAAWpB,UAC1EoB,EAAWnB,cAAgBoB,EAASpB,cAAakB,EAASlB,YAAcmB,EAAWnB,aACnFmB,EAAWlB,iBAAmBmB,EAASnB,iBAAgBiB,EAASjB,eAAiBkB,EAAWlB,gBAC5FkB,EAAWjB,YAAckB,EAASlB,YAAWgB,EAAShB,UAAYiB,EAAWjB,WAC7EiB,EAAWhB,aAAeiB,EAASjB,aAAYe,EAASf,WAAagB,EAAWhB,YAE7Ee,CACT,CAEQ,IAAAV,GAENvB,KAAKoC,eAGLpC,KAAKqC,eAGDrC,KAAKD,OAAOiB,gBACdhB,KAAKsC,WAAW,YAAatC,KAAKD,OAAOiB,eAE7C,CAEQ,YAAAoB,GACN,MAAMG,EAAU,kBAChB,GAAIC,SAASC,eAAeF,GAAU,OAEtC,MAAMG,EAAQF,SAASG,cAAc,SACrCD,EAAME,GAAKL,EACXG,EAAMG,YFtGe,EAACjC,EAAuB,YAAc,6CAE3CA,kDACyBA,wvTEmGrBkC,CAAU9C,KAAKD,OAAOa,cAC1C4B,SAASO,KAAKC,YAAYN,EAC5B,CAEQ,YAAAL,GAENrC,KAAKC,UAAYuC,SAASG,cAAc,OACxC3C,KAAKC,UAAUgD,UAAY,oBAAyC,UAAtBjD,KAAKD,OAAOY,MAAoB,QAAU,IAGxF,MAAMuC,EAAMV,SAASG,cAAc,UACnCO,EAAID,UAAY,iBAAyC,gBAAzBjD,KAAKD,OAAOW,SAA6B,OAAS,IAClFwC,EAAIC,UAAYvD,EAChBsD,EAAIE,QAAU,IAAMpD,KAAKqD,SAGzBrD,KAAKE,MAAQsC,SAASG,cAAc,OACpC3C,KAAKE,MAAM+C,UAAY,mBAA2C,gBAAzBjD,KAAKD,OAAOW,SAA6B,OAAS,IAC3FV,KAAKE,MAAMiD,UAAYnD,KAAKsD,eAG5BtD,KAAKC,UAAU+C,YAAYE,GAC3BlD,KAAKC,UAAU+C,YAAYhD,KAAKE,OAChCsC,SAASe,KAAKP,YAAYhD,KAAKC,WAG/BD,KAAKG,kBAAoBH,KAAKE,MAAMsD,cAAc,sBAClDxD,KAAKI,MAAQJ,KAAKE,MAAMsD,cAAc,mBAGtC,MAAMC,EAAWzD,KAAKE,MAAMsD,cAAc,mBAC1CC,GAAUC,iBAAiB,QAAS,IAAM1D,KAAK2D,SAE/C,MAAMC,EAAU5D,KAAKE,MAAMsD,cAAc,kBAWzC,GAVAI,GAASF,iBAAiB,QAAS,IAAM1D,KAAK6D,eAE9C7D,KAAKI,OAAOsD,iBAAiB,WAAaI,IAC1B,UAAVA,EAAEC,KAAoBD,EAAEE,WAC1BF,EAAEG,iBACFjE,KAAK6D,iBAKiB,SAAtB7D,KAAKD,OAAOY,MAAkB,CAChC,MAAMuD,EAAaC,OAAOC,WAAW,iCACrCpE,KAAKqE,YAAYH,EAAWI,SAC5BJ,EAAWR,iBAAiB,SAAWI,GAAM9D,KAAKqE,YAAYP,EAAEQ,SAClE,CACF,CAEQ,YAAAhB,GACN,MAAMiB,EAAgBvE,KAAKD,OAAOmB,WAC9B,GACA,+HAIJ,MAAO,gIAG8BtB,oEAEAI,KAAKD,OAAOc,wDACVb,KAAKD,OAAOe,+dAOUd,KAAKD,OAAOgB,4TAGrEwD,SAEN,CAEQ,WAAAF,CAAYG,GACdA,EACFxE,KAAKC,WAAWwE,UAAUC,IAAI,SAE9B1E,KAAKC,WAAWwE,UAAUE,OAAO,QAErC,CAEO,MAAAtB,GACLrD,KAAKK,OAASL,KAAK2D,QAAU3D,KAAK4E,MACpC,CAEO,IAAAA,GACL5E,KAAKK,QAAS,EACdL,KAAKE,OAAOuE,UAAUC,IAAI,QAC1B1E,KAAKI,OAAOyE,OACd,CAEO,KAAAlB,GACL3D,KAAKK,QAAS,EACdL,KAAKE,OAAOuE,UAAUE,OAAO,OAC/B,CAEQ,UAAArC,CAAWwC,EAA4BC,GAC7C,MAAMC,EAAmB,CACvBpC,GAAI,OAAOqC,KAAKC,QAChBJ,OACAC,UACAI,UAAW,IAAIF,MAGjBjF,KAAKM,SAAS8E,KAAKJ,GACnBhF,KAAKqF,cAAcL,EACrB,CAEQ,aAAAK,CAAcL,GACpB,IAAKhF,KAAKG,kBAAmB,OAE7B,MAAMmF,EAAK9C,SAASG,cAAc,OAClC2C,EAAGrC,UAAY,oBAAoB+B,EAAQF,OAC3CQ,EAAGnC,UAAYnD,KAAKuF,cAAcP,EAAQD,SAE1C/E,KAAKG,kBAAkB6C,YAAYsC,GACnCtF,KAAKwF,gBACP,CAEQ,aAAAD,CAAcR,GAEpB,MAAMU,EAAcC,GACXA,EACJC,QAAQ,KAAM,SACdA,QAAQ,KAAM,QACdA,QAAQ,KAAM,QACdA,QAAQ,KAAM,UACdA,QAAQ,KAAM,UAKbC,EAAuB,GAC7B,IAAIC,EAAYd,EAAQY,QAAQ,kCAAmC,CAACG,EAAGC,EAAMC,KAC3E,MAAMC,EAAUR,EAAWO,EAAKE,QAC1BC,EAAYJ,EAAO,mBAAmBN,EAAWM,MAAW,GAElE,OADAH,EAAWR,KAAK,mCAAmCe,WAAmBF,kBAC/D,cAAcL,EAAWQ,OAAS,QAI3C,MAAMC,EAAwB,GA0D9B,OAzDAR,EAAYA,EAAUF,QAAQ,aAAc,CAACG,EAAGE,KAC9CK,EAAYjB,KAAK,sCAAsCK,EAAWO,aAC3D,eAAeK,EAAYD,OAAS,QAI7CP,EAAYJ,EAAWI,GAGvBA,EAAYA,EAAUF,QAAQ,eAAgB,mCAC9CE,EAAYA,EAAUF,QAAQ,cAAe,mCAC7CE,EAAYA,EAAUF,QAAQ,aAAc,mCAG5CE,EAAYA,EAAUF,QAAQ,uBAAwB,gCACtDE,EAAYA,EAAUF,QAAQ,mBAAoB,uBAClDE,EAAYA,EAAUF,QAAQ,eAAgB,eAC9CE,EAAYA,EAAUF,QAAQ,aAAc,eAG5CE,EAAYA,EAAUF,QAAQ,2BAA4B,uFAG1DE,EAAYA,EAAUF,QAAQ,kBAAmB,mCACjDE,EAAYA,EAAUF,QAAQ,0CAA4CW,GACjE,2BAA2BA,UAIpCT,EAAYA,EAAUF,QAAQ,iBAAkB,2CAChDE,EAAYA,EAAUF,QAAQ,kDAAoDW,GACzE,2BAA2BA,UAIpCT,EAAYA,EAAUF,QAAQ,UAAW,4BAGzCE,EAAYA,EAAUF,QAAQ,gBAAiB,2DAG/CE,EAAYA,EAAUF,QAAQ,MAAO,QAGrCE,EAAYA,EAAUF,QAAQ,yCAA0C,SACxEE,EAAYA,EAAUF,QAAQ,sCAAuC,OAGrEC,EAAWW,QAAQ,CAACC,EAAOC,KACzBZ,EAAYA,EAAUF,QAAQ,cAAcc,MAAOD,KAIrDH,EAAYE,QAAQ,CAACP,EAAMS,KACzBZ,EAAYA,EAAUF,QAAQ,eAAec,MAAOT,KAG/CH,CACT,CAEQ,UAAAa,GACN,MAAMC,EAASnE,SAASG,cAAc,OAKtC,OAJAgE,EAAO1D,UAAY,kBACnB0D,EAAOxD,UAAY,0CACnBnD,KAAKG,mBAAmB6C,YAAY2D,GACpC3G,KAAKwF,iBACEmB,CACT,CAEQ,cAAAnB,GACFxF,KAAKG,oBACPH,KAAKG,kBAAkByG,UAAY5G,KAAKG,kBAAkB0G,aAE9D,CAEQ,iBAAMhD,GACZ,IAAK7D,KAAKI,OAASJ,KAAKO,UAAW,OAEnC,MAAMwE,EAAU/E,KAAKI,MAAM0G,MAAMZ,OACjC,IAAKnB,EAAS,OAGd/E,KAAKsC,WAAW,OAAQyC,GACxB/E,KAAKI,MAAM0G,MAAQ,GAGnB9G,KAAKO,WAAY,EACjB,MAAMoG,EAAS3G,KAAK0G,aAEpB,IACE,GAAI1G,KAAKD,OAAOkB,gBACRjB,KAAK+G,iBAAiBhC,EAAS4B,OAChC,CACL,MAAMjF,QAAiB1B,KAAKgH,QAAQjC,GACpC4B,EAAOhC,SAEHjD,EAASD,MACXzB,KAAKsC,WAAW,YAAa,kCAAkCZ,EAASD,SAExEzB,KAAKsC,WAAW,YAAaZ,EAASA,SAE1C,CACF,CAAE,MAAOD,GACPkF,EAAOhC,SACP3E,KAAKsC,WAAW,YAAa,sDAC7Bd,QAAQC,MAAM,kBAAmBA,EACnC,SACEzB,KAAKO,WAAY,CACnB,CACF,CAEQ,sBAAMwG,CAAiB/B,EAAiB2B,GAC9C,MAAMjF,QAAiBC,MAAM,GAAG3B,KAAKD,OAAOU,cAAe,CACzDwG,OAAQ,OACRC,QAAS,CACP,eAAgB,mBAChBC,cAAe,UAAUnH,KAAKD,OAAOqB,UAEvCmC,KAAM6D,KAAKC,UAAU,CACnBrC,UACAsC,QAAStH,KAAKuH,yBACdC,QAAQ,MAIZ,IAAK9F,EAASE,GAAI,CAChB+E,EAAOhC,SACP,MAAMlD,QAAcC,EAASI,OAAO2F,MAAM,MAAShG,MAAO,oBAE1D,YADAzB,KAAKsC,WAAW,YAAa,kCAAkCb,EAAMA,OAAS,mBAEhF,CAGAkF,EAAOhC,SACP,MAAM+C,EAAYlF,SAASG,cAAc,OACzC+E,EAAUzE,UAAY,6BACtBjD,KAAKG,mBAAmB6C,YAAY0E,GAEpC,MAAMC,EAASjG,EAAS6B,MAAMqE,YAC9B,IAAKD,EAEH,YADA3H,KAAKsC,WAAW,YAAa,sCAI/B,MAAMuF,EAAU,IAAIC,YACpB,IAAIC,EAAc,GAElB,IACE,OAAa,CACX,MAAMC,KAAEA,EAAIlB,MAAEA,SAAgBa,EAAOM,OACrC,GAAID,EAAM,MAEV,MACME,EADQL,EAAQM,OAAOrB,EAAO,CAAEU,QAAQ,IAC1BY,MAAM,MAAMC,OAAQC,GAAyB,KAAhBA,EAAKpC,QAEtD,IAAK,MAAMoC,KAAQJ,EACjB,GAAII,EAAKC,WAAW,UAAW,CAC7B,MAAMC,EAAOF,EAAKG,MAAM,GACxB,GAAa,WAATD,EAAmB,SAEvB,IACE,MAAME,EAAStB,KAAKuB,MAAMH,GACtBE,EAAO3D,UACTgD,GAAeW,EAAO3D,QACtB2C,EAAUvE,UAAYnD,KAAKuF,cAAcwC,GACzC/H,KAAKwF,iBAET,CAAE,MAEF,CACF,CAEJ,CACF,CAAE,MAAO/D,GACPD,QAAQC,MAAM,wBAAyBA,EACzC,CAGAzB,KAAKM,SAAS8E,KAAK,CACjBxC,GAAI,OAAOqC,KAAKC,QAChBJ,KAAM,YACNC,QAASgD,EACT5C,UAAW,IAAIF,MAEnB,CAEQ,aAAM+B,CAAQhC,GACpB,MAAMtD,QAAiBC,MAAM,GAAG3B,KAAKD,OAAOU,cAAe,CACzDwG,OAAQ,OACRC,QAAS,CACP,eAAgB,mBAChBC,cAAe,UAAUnH,KAAKD,OAAOqB,UAEvCmC,KAAM6D,KAAKC,UAAU,CACnBrC,UACAsC,QAAStH,KAAKuH,6BAIlB,IAAK7F,EAASE,GAAI,CAEhB,MAAO,CAAEF,SAAU,GAAID,aADHC,EAASI,OAAO2F,MAAM,MAAShG,MAAO,qBACtBA,OAAS,iBAC/C,CAEA,OAAOC,EAASI,MAClB,CAEQ,sBAAAyF,GAEN,OAAOvH,KAAKM,SAASmI,OAAM,IAAKG,IAAKC,IAAC,CACpC/D,KAAM+D,EAAE/D,KACRC,QAAS8D,EAAE9D,UAEf,CAEO,OAAA+D,GACL9I,KAAKC,WAAW0E,SAChBnC,SAASC,eAAe,oBAAoBkC,QAC9C,SC/cF,WAEE,MAAMoE,EAASvG,SAASwG,eACnBxG,SAASgB,cAAc,qCAE5B,IAAKuF,EAEH,YADAvH,QAAQQ,KAAK,uCAKf,MAAMjC,EAAyB,CAC7BqB,OAAQ2H,EAAOE,QAAQlF,KAAOgF,EAAOE,QAAQ7H,QAAU,GACvDX,OAAQsI,EAAOE,QAAQxI,QAAU,0BACjCC,SAAWqI,EAAOE,QAAQvI,UAA+C,eACzEC,MAAQoI,EAAOE,QAAQtI,OAAuC,OAC9DC,aAAcmI,EAAOE,QAAQC,OAAS,UACtCrI,MAAOkI,EAAOE,QAAQpI,OAAS,YAC/BC,SAAUiI,EAAOE,QAAQnI,UAAY,6BACrCC,YAAagI,EAAOE,QAAQlI,aAAe,oBAC3CC,eAAgB+H,EAAOE,QAAQE,SAAW,qFAC1ClI,UAAwC,UAA7B8H,EAAOE,QAAQhI,WAGvBlB,EAAOqB,OAMgB,YAAxBoB,SAAS4G,WACX5G,SAASkB,iBAAiB,mBAAoB,KAC3CS,OAAekF,SAAW,IAAIxJ,EAAeE,KAG/CoE,OAAekF,SAAW,IAAIxJ,EAAeE,GAV9CyB,QAAQC,MAAM,uCAYjB,CArCD"}
1
+ {"version":3,"file":"librebot.js","sources":["../src/styles.ts","../src/icons.ts","../src/widget.ts","../src/embed.ts"],"sourcesContent":["export const getStyles = (primaryColor: string = '#14b8a6') => `\n .librebot-widget {\n --lb-primary: ${primaryColor};\n --lb-primary-hover: color-mix(in srgb, ${primaryColor} 85%, white);\n --lb-bg: #0f0f0f;\n --lb-bg-secondary: #1a1a1a;\n --lb-text: #ffffff;\n --lb-text-secondary: #9ca3af;\n --lb-border: #2a2a2a;\n font-family: 'Roboto Mono', -apple-system, BlinkMacSystemFont, 'Segoe UI', monospace;\n font-size: 14px;\n line-height: 1.5;\n }\n\n .librebot-widget.light {\n --lb-bg: #ffffff;\n --lb-bg-secondary: #f5f5f5;\n --lb-text: #1a1a1a;\n --lb-text-secondary: #666666;\n --lb-border: #e0e0e0;\n }\n\n .librebot-fab {\n position: fixed;\n bottom: 20px;\n right: 20px;\n width: 56px;\n height: 56px;\n border-radius: 50%;\n background: var(--lb-primary);\n border: none;\n cursor: pointer;\n box-shadow: 0 4px 12px rgba(0, 0, 0, 0.3);\n display: flex;\n align-items: center;\n justify-content: center;\n transition: transform 0.2s, box-shadow 0.2s;\n z-index: 999998;\n }\n\n .librebot-fab:hover {\n transform: scale(1.05);\n box-shadow: 0 6px 16px rgba(0, 0, 0, 0.4);\n }\n\n .librebot-fab svg {\n width: 24px;\n height: 24px;\n fill: white;\n }\n\n .librebot-fab.left {\n right: auto;\n left: 20px;\n }\n\n .librebot-modal {\n position: fixed;\n bottom: 90px;\n right: 20px;\n width: 380px;\n max-width: calc(100vw - 40px);\n height: 520px;\n max-height: calc(100vh - 120px);\n background: var(--lb-bg);\n border: 1px solid var(--lb-border);\n border-radius: 16px;\n box-shadow: 0 8px 32px rgba(0, 0, 0, 0.3);\n display: flex;\n flex-direction: column;\n overflow: hidden;\n z-index: 999999;\n opacity: 0;\n transform: translateY(20px) scale(0.95);\n transition: opacity 0.2s, transform 0.2s;\n pointer-events: none;\n }\n\n .librebot-modal.open {\n opacity: 1;\n transform: translateY(0) scale(1);\n pointer-events: auto;\n }\n\n .librebot-modal.left {\n right: auto;\n left: 20px;\n }\n\n .librebot-header {\n padding: 16px;\n border-bottom: 1px solid var(--lb-border);\n display: flex;\n align-items: center;\n justify-content: space-between;\n }\n\n .librebot-header-content {\n display: flex;\n align-items: center;\n gap: 12px;\n }\n\n .librebot-avatar {\n width: 40px;\n height: 40px;\n border-radius: 10px;\n background: var(--lb-primary);\n display: flex;\n align-items: center;\n justify-content: center;\n }\n\n .librebot-avatar svg {\n width: 24px;\n height: 24px;\n fill: white;\n }\n\n .librebot-title {\n font-weight: 600;\n color: var(--lb-text);\n margin: 0;\n font-size: 16px;\n }\n\n .librebot-subtitle {\n font-size: 12px;\n color: var(--lb-text-secondary);\n margin: 0;\n }\n\n .librebot-close {\n width: 32px;\n height: 32px;\n border-radius: 8px;\n border: none;\n background: transparent;\n cursor: pointer;\n display: flex;\n align-items: center;\n justify-content: center;\n color: var(--lb-text-secondary);\n transition: background 0.2s;\n }\n\n .librebot-close:hover {\n background: var(--lb-bg-secondary);\n }\n\n .librebot-messages {\n flex: 1;\n overflow-y: auto;\n padding: 16px;\n display: flex;\n flex-direction: column;\n gap: 12px;\n }\n\n .librebot-message {\n max-width: 85%;\n padding: 10px 14px;\n border-radius: 16px;\n word-wrap: break-word;\n }\n\n .librebot-message.user {\n align-self: flex-end;\n background: var(--lb-primary);\n color: white;\n border-bottom-right-radius: 4px;\n }\n\n .librebot-message.assistant {\n align-self: flex-start;\n background: var(--lb-bg-secondary);\n color: var(--lb-text);\n border-bottom-left-radius: 4px;\n }\n\n /* Inline code */\n .librebot-inline-code {\n background: rgba(0, 0, 0, 0.3);\n padding: 2px 6px;\n border-radius: 4px;\n font-family: 'Roboto Mono', 'Fira Code', 'Consolas', monospace;\n font-size: 12px;\n color: #f0f0f0;\n }\n\n .librebot-widget.light .librebot-inline-code {\n background: rgba(0, 0, 0, 0.08);\n color: #1a1a1a;\n }\n\n /* Code blocks */\n .librebot-code-block {\n background: #0d1117;\n padding: 12px 14px;\n border-radius: 8px;\n overflow-x: auto;\n margin: 10px 0;\n border: 1px solid rgba(255, 255, 255, 0.1);\n position: relative;\n }\n\n .librebot-widget.light .librebot-code-block {\n background: #f6f8fa;\n border-color: rgba(0, 0, 0, 0.1);\n }\n\n .librebot-code-block code {\n font-family: 'Roboto Mono', 'Fira Code', 'Consolas', monospace;\n font-size: 12px;\n line-height: 1.5;\n color: #e6edf3;\n background: none;\n padding: 0;\n white-space: pre;\n display: block;\n }\n\n .librebot-widget.light .librebot-code-block code {\n color: #24292f;\n }\n\n .librebot-code-block[data-language]::before {\n content: attr(data-language);\n position: absolute;\n top: 6px;\n right: 10px;\n font-size: 10px;\n color: rgba(255, 255, 255, 0.4);\n text-transform: uppercase;\n font-family: 'Roboto Mono', monospace;\n }\n\n .librebot-widget.light .librebot-code-block[data-language]::before {\n color: rgba(0, 0, 0, 0.3);\n }\n\n /* Headers */\n .librebot-h2 {\n font-size: 16px;\n font-weight: 600;\n margin: 12px 0 8px 0;\n color: var(--lb-text);\n }\n\n .librebot-h3 {\n font-size: 14px;\n font-weight: 600;\n margin: 10px 0 6px 0;\n color: var(--lb-text);\n }\n\n .librebot-h4 {\n font-size: 13px;\n font-weight: 600;\n margin: 8px 0 4px 0;\n color: var(--lb-text);\n }\n\n /* Lists */\n .librebot-ul, .librebot-ol {\n margin: 8px 0;\n padding-left: 20px;\n }\n\n .librebot-ul {\n list-style-type: disc;\n }\n\n .librebot-ol {\n list-style-type: decimal;\n }\n\n .librebot-li, .librebot-li-ordered {\n margin: 4px 0;\n padding-left: 4px;\n line-height: 1.5;\n }\n\n /* Links */\n .librebot-link {\n color: var(--lb-primary);\n text-decoration: none;\n border-bottom: 1px solid transparent;\n transition: border-color 0.2s;\n }\n\n .librebot-link:hover {\n border-bottom-color: var(--lb-primary);\n }\n\n /* Blockquotes */\n .librebot-blockquote {\n border-left: 3px solid var(--lb-primary);\n margin: 8px 0;\n padding: 4px 12px;\n color: var(--lb-text-secondary);\n font-style: italic;\n background: rgba(0, 0, 0, 0.1);\n border-radius: 0 6px 6px 0;\n }\n\n .librebot-widget.light .librebot-blockquote {\n background: rgba(0, 0, 0, 0.04);\n }\n\n /* Horizontal rule */\n .librebot-hr {\n border: none;\n border-top: 1px solid var(--lb-border);\n margin: 12px 0;\n }\n\n /* Strong and emphasis */\n .librebot-message strong {\n font-weight: 600;\n }\n\n .librebot-message em {\n font-style: italic;\n }\n\n /* Legacy support for old code elements */\n .librebot-message code:not(.librebot-inline-code) {\n background: rgba(0, 0, 0, 0.2);\n padding: 2px 6px;\n border-radius: 4px;\n font-family: monospace;\n font-size: 13px;\n }\n\n .librebot-message pre:not(.librebot-code-block) {\n background: rgba(0, 0, 0, 0.3);\n padding: 10px;\n border-radius: 8px;\n overflow-x: auto;\n margin: 8px 0;\n }\n\n .librebot-message pre:not(.librebot-code-block) code {\n background: none;\n padding: 0;\n }\n\n .librebot-typing {\n display: flex;\n gap: 4px;\n padding: 12px 16px;\n align-self: flex-start;\n background: var(--lb-bg-secondary);\n border-radius: 16px;\n border-bottom-left-radius: 4px;\n }\n\n .librebot-typing span {\n width: 8px;\n height: 8px;\n background: var(--lb-text-secondary);\n border-radius: 50%;\n animation: librebot-bounce 1.4s infinite ease-in-out;\n }\n\n .librebot-typing span:nth-child(1) { animation-delay: 0s; }\n .librebot-typing span:nth-child(2) { animation-delay: 0.2s; }\n .librebot-typing span:nth-child(3) { animation-delay: 0.4s; }\n\n @keyframes librebot-bounce {\n 0%, 80%, 100% { transform: scale(0.8); opacity: 0.5; }\n 40% { transform: scale(1); opacity: 1; }\n }\n\n .librebot-input-area {\n padding: 12px 16px;\n border-top: 1px solid var(--lb-border);\n display: flex;\n gap: 8px;\n }\n\n .librebot-input {\n flex: 1;\n padding: 10px 14px;\n border: 1px solid var(--lb-border);\n border-radius: 24px;\n background: var(--lb-bg-secondary);\n color: var(--lb-text);\n font-size: 14px;\n outline: none;\n transition: border-color 0.2s;\n }\n\n .librebot-input:focus {\n border-color: var(--lb-primary);\n }\n\n .librebot-input::placeholder {\n color: var(--lb-text-secondary);\n }\n\n .librebot-send {\n width: 40px;\n height: 40px;\n border-radius: 50%;\n border: none;\n background: var(--lb-primary);\n cursor: pointer;\n display: flex;\n align-items: center;\n justify-content: center;\n transition: background 0.2s;\n }\n\n .librebot-send:hover {\n background: var(--lb-primary-hover);\n }\n\n .librebot-send:disabled {\n opacity: 0.5;\n cursor: not-allowed;\n }\n\n .librebot-send svg {\n width: 18px;\n height: 18px;\n fill: white;\n }\n\n .librebot-welcome {\n text-align: center;\n padding: 20px;\n color: var(--lb-text-secondary);\n }\n\n .librebot-welcome-icon {\n width: 48px;\n height: 48px;\n margin: 0 auto 12px;\n background: var(--lb-primary);\n border-radius: 12px;\n display: flex;\n align-items: center;\n justify-content: center;\n }\n\n .librebot-welcome-icon svg {\n width: 28px;\n height: 28px;\n fill: white;\n }\n\n .librebot-powered {\n text-align: center;\n padding: 8px;\n font-size: 11px;\n color: var(--lb-text-secondary);\n border-top: 1px solid var(--lb-border);\n }\n\n .librebot-powered a {\n color: var(--lb-primary);\n text-decoration: none;\n }\n\n .librebot-powered a:hover {\n text-decoration: underline;\n }\n`;\n","export const chatIcon = `<svg viewBox=\"0 0 24 24\" fill=\"none\" stroke=\"currentColor\" stroke-width=\"2\" stroke-linecap=\"round\" stroke-linejoin=\"round\"><path d=\"M21 15a2 2 0 0 1-2 2H7l-4 4V5a2 2 0 0 1 2-2h14a2 2 0 0 1 2 2z\"></path></svg>`;\n\nexport const closeIcon = `<svg viewBox=\"0 0 24 24\" fill=\"none\" stroke=\"currentColor\" stroke-width=\"2\" stroke-linecap=\"round\" stroke-linejoin=\"round\"><line x1=\"18\" y1=\"6\" x2=\"6\" y2=\"18\"></line><line x1=\"6\" y1=\"6\" x2=\"18\" y2=\"18\"></line></svg>`;\n\nexport const sendIcon = `<svg viewBox=\"0 0 24 24\" fill=\"none\" stroke=\"currentColor\" stroke-width=\"2\" stroke-linecap=\"round\" stroke-linejoin=\"round\"><line x1=\"22\" y1=\"2\" x2=\"11\" y2=\"13\"></line><polygon points=\"22 2 15 22 11 13 2 9 22 2\"></polygon></svg>`;\n\nexport const botIcon = `<svg viewBox=\"0 0 24 24\" fill=\"currentColor\"><path d=\"M12 2C6.48 2 2 6.48 2 12s4.48 10 10 10 10-4.48 10-10S17.52 2 12 2zm-2 15l-5-5 1.41-1.41L10 14.17l7.59-7.59L19 8l-9 9z\"/></svg>`;\n","import { LibreBotConfig, Message, ChatResponse } from './types';\nimport { getStyles } from './styles';\nimport { chatIcon, closeIcon, sendIcon } from './icons';\n\nexport class LibreBotWidget {\n private config!: Required<LibreBotConfig>;\n private container: HTMLDivElement | null = null;\n private modal: HTMLDivElement | null = null;\n private messagesContainer: HTMLDivElement | null = null;\n private input: HTMLInputElement | null = null;\n private isOpen = false;\n private messages: Message[] = [];\n private isLoading = false;\n private sessionId: string | null = null;\n\n private defaultConfig: Omit<Required<LibreBotConfig>, 'apiKey'> = {\n apiUrl: 'https://librebot.io/api',\n position: 'bottom-right',\n theme: 'dark',\n primaryColor: '#14b8a6',\n title: 'Libre Bot',\n subtitle: 'AI Documentation Assistant',\n placeholder: 'Ask a question...',\n welcomeMessage: 'Hi! I can help you find answers in the documentation. What would you like to know?',\n streaming: true,\n whiteLabel: false,\n autoLoadConfig: true,\n };\n\n constructor(config: LibreBotConfig) {\n if (!config.apiKey) {\n console.error('LibreBot: API key is required');\n return;\n }\n\n this.config = { ...this.defaultConfig, ...config } as Required<LibreBotConfig>;\n\n // Auto-load config from server if enabled and no custom settings provided\n if (this.config.autoLoadConfig) {\n this.loadRemoteConfig().then(() => this.init());\n } else {\n this.init();\n }\n }\n\n private async loadRemoteConfig(): Promise<void> {\n try {\n const response = await fetch(`${this.config.apiUrl}/widget-config?key=${this.config.apiKey}`);\n if (response.ok) {\n const remoteConfig = await response.json();\n // Merge remote config with local config (local overrides remote)\n this.config = {\n ...this.defaultConfig,\n ...remoteConfig,\n ...this.getProvidedConfig(),\n apiKey: this.config.apiKey,\n apiUrl: this.config.apiUrl,\n autoLoadConfig: this.config.autoLoadConfig,\n } as Required<LibreBotConfig>;\n }\n } catch (error) {\n console.warn('LibreBot: Could not load remote config, using defaults', error);\n }\n }\n\n private getProvidedConfig(): Partial<LibreBotConfig> {\n // Return only the config options that were explicitly provided (not default values)\n const provided: Partial<LibreBotConfig> = {};\n const userConfig = this.config;\n const defaults = this.defaultConfig;\n\n if (userConfig.position !== defaults.position) provided.position = userConfig.position;\n if (userConfig.theme !== defaults.theme) provided.theme = userConfig.theme;\n if (userConfig.primaryColor !== defaults.primaryColor) provided.primaryColor = userConfig.primaryColor;\n if (userConfig.title !== defaults.title) provided.title = userConfig.title;\n if (userConfig.subtitle !== defaults.subtitle) provided.subtitle = userConfig.subtitle;\n if (userConfig.placeholder !== defaults.placeholder) provided.placeholder = userConfig.placeholder;\n if (userConfig.welcomeMessage !== defaults.welcomeMessage) provided.welcomeMessage = userConfig.welcomeMessage;\n if (userConfig.streaming !== defaults.streaming) provided.streaming = userConfig.streaming;\n if (userConfig.whiteLabel !== defaults.whiteLabel) provided.whiteLabel = userConfig.whiteLabel;\n\n return provided;\n }\n\n private init(): void {\n // Load sessionId from localStorage for persistent memory\n this.loadSession();\n\n // Inject styles\n this.injectStyles();\n\n // Create widget container\n this.createWidget();\n\n // Add welcome message\n if (this.config.welcomeMessage) {\n this.addMessage('assistant', this.config.welcomeMessage);\n }\n }\n\n private getSessionKey(): string {\n return `librebot_session_${this.config.apiKey}`;\n }\n\n private loadSession(): void {\n try {\n const stored = localStorage.getItem(this.getSessionKey());\n if (stored) {\n this.sessionId = stored;\n }\n } catch {\n // localStorage may not be available\n }\n }\n\n private saveSession(sessionId: string): void {\n try {\n this.sessionId = sessionId;\n localStorage.setItem(this.getSessionKey(), sessionId);\n } catch {\n // localStorage may not be available\n }\n }\n\n private injectStyles(): void {\n const styleId = 'librebot-styles';\n if (document.getElementById(styleId)) return;\n\n const style = document.createElement('style');\n style.id = styleId;\n style.textContent = getStyles(this.config.primaryColor);\n document.head.appendChild(style);\n }\n\n private createWidget(): void {\n // Create container\n this.container = document.createElement('div');\n this.container.className = `librebot-widget ${this.config.theme === 'light' ? 'light' : ''}`;\n\n // Create FAB button\n const fab = document.createElement('button');\n fab.className = `librebot-fab ${this.config.position === 'bottom-left' ? 'left' : ''}`;\n fab.innerHTML = chatIcon;\n fab.onclick = () => this.toggle();\n\n // Create modal\n this.modal = document.createElement('div');\n this.modal.className = `librebot-modal ${this.config.position === 'bottom-left' ? 'left' : ''}`;\n this.modal.innerHTML = this.getModalHTML();\n\n // Add to container\n this.container.appendChild(fab);\n this.container.appendChild(this.modal);\n document.body.appendChild(this.container);\n\n // Get references\n this.messagesContainer = this.modal.querySelector('.librebot-messages');\n this.input = this.modal.querySelector('.librebot-input');\n\n // Add event listeners\n const closeBtn = this.modal.querySelector('.librebot-close');\n closeBtn?.addEventListener('click', () => this.close());\n\n const sendBtn = this.modal.querySelector('.librebot-send');\n sendBtn?.addEventListener('click', () => this.sendMessage());\n\n this.input?.addEventListener('keypress', (e) => {\n if (e.key === 'Enter' && !e.shiftKey) {\n e.preventDefault();\n this.sendMessage();\n }\n });\n\n // Auto theme detection\n if (this.config.theme === 'auto') {\n const mediaQuery = window.matchMedia('(prefers-color-scheme: light)');\n this.updateTheme(mediaQuery.matches);\n mediaQuery.addEventListener('change', (e) => this.updateTheme(e.matches));\n }\n }\n\n private getModalHTML(): string {\n const poweredByHtml = this.config.whiteLabel\n ? ''\n : `<div class=\"librebot-powered\">\n Powered by <a href=\"https://librebot.io\" target=\"_blank\">Libre Bot</a>\n </div>`;\n\n return `\n <div class=\"librebot-header\">\n <div class=\"librebot-header-content\">\n <div class=\"librebot-avatar\">${chatIcon}</div>\n <div>\n <h3 class=\"librebot-title\">${this.config.title}</h3>\n <p class=\"librebot-subtitle\">${this.config.subtitle}</p>\n </div>\n </div>\n <button class=\"librebot-close\">${closeIcon}</button>\n </div>\n <div class=\"librebot-messages\"></div>\n <div class=\"librebot-input-area\">\n <input type=\"text\" class=\"librebot-input\" placeholder=\"${this.config.placeholder}\" />\n <button class=\"librebot-send\">${sendIcon}</button>\n </div>\n ${poweredByHtml}\n `;\n }\n\n private updateTheme(isLight: boolean): void {\n if (isLight) {\n this.container?.classList.add('light');\n } else {\n this.container?.classList.remove('light');\n }\n }\n\n public toggle(): void {\n this.isOpen ? this.close() : this.open();\n }\n\n public open(): void {\n this.isOpen = true;\n this.modal?.classList.add('open');\n this.input?.focus();\n }\n\n public close(): void {\n this.isOpen = false;\n this.modal?.classList.remove('open');\n }\n\n private addMessage(role: 'user' | 'assistant', content: string): void {\n const message: Message = {\n id: `msg-${Date.now()}`,\n role,\n content,\n timestamp: new Date(),\n };\n\n this.messages.push(message);\n this.renderMessage(message);\n }\n\n private renderMessage(message: Message): void {\n if (!this.messagesContainer) return;\n\n const el = document.createElement('div');\n el.className = `librebot-message ${message.role}`;\n el.innerHTML = this.formatMessage(message.content);\n\n this.messagesContainer.appendChild(el);\n this.scrollToBottom();\n }\n\n private formatMessage(content: string): string {\n // Escape HTML to prevent XSS\n const escapeHtml = (text: string): string => {\n return text\n .replace(/&/g, '&amp;')\n .replace(/</g, '&lt;')\n .replace(/>/g, '&gt;')\n .replace(/\"/g, '&quot;')\n .replace(/'/g, '&#039;');\n };\n\n // First, extract code blocks to protect them from other formatting\n // Regex handles optional space/newline after ``` and optional language identifier\n const codeBlocks: string[] = [];\n let processed = content.replace(/```\\s*(\\w*)\\s*\\n?([\\s\\S]*?)```/g, (_, lang, code) => {\n const escaped = escapeHtml(code.trim());\n const langClass = lang ? ` data-language=\"${escapeHtml(lang)}\"` : '';\n codeBlocks.push(`<pre class=\"librebot-code-block\"${langClass}><code>${escaped}</code></pre>`);\n return `%%CODEBLOCK${codeBlocks.length - 1}%%`;\n });\n\n // Extract inline code\n const inlineCodes: string[] = [];\n processed = processed.replace(/`([^`]+)`/g, (_, code) => {\n inlineCodes.push(`<code class=\"librebot-inline-code\">${escapeHtml(code)}</code>`);\n return `%%INLINECODE${inlineCodes.length - 1}%%`;\n });\n\n // Now escape remaining HTML\n processed = escapeHtml(processed);\n\n // Headers (## and ###)\n processed = processed.replace(/^### (.+)$/gm, '<h4 class=\"librebot-h4\">$1</h4>');\n processed = processed.replace(/^## (.+)$/gm, '<h3 class=\"librebot-h3\">$1</h3>');\n processed = processed.replace(/^# (.+)$/gm, '<h2 class=\"librebot-h2\">$1</h2>');\n\n // Bold and italic\n processed = processed.replace(/\\*\\*\\*([^*]+)\\*\\*\\*/g, '<strong><em>$1</em></strong>');\n processed = processed.replace(/\\*\\*([^*]+)\\*\\*/g, '<strong>$1</strong>');\n processed = processed.replace(/\\*([^*]+)\\*/g, '<em>$1</em>');\n processed = processed.replace(/_([^_]+)_/g, '<em>$1</em>');\n\n // Links [text](url)\n processed = processed.replace(/\\[([^\\]]+)\\]\\(([^)]+)\\)/g, '<a href=\"$2\" target=\"_blank\" rel=\"noopener noreferrer\" class=\"librebot-link\">$1</a>');\n\n // Unordered lists\n processed = processed.replace(/^[\\*\\-] (.+)$/gm, '<li class=\"librebot-li\">$1</li>');\n processed = processed.replace(/(<li class=\"librebot-li\">.*<\\/li>\\n?)+/g, (match) => {\n return `<ul class=\"librebot-ul\">${match}</ul>`;\n });\n\n // Ordered lists\n processed = processed.replace(/^\\d+\\. (.+)$/gm, '<li class=\"librebot-li-ordered\">$1</li>');\n processed = processed.replace(/(<li class=\"librebot-li-ordered\">.*<\\/li>\\n?)+/g, (match) => {\n return `<ol class=\"librebot-ol\">${match}</ol>`;\n });\n\n // Horizontal rule\n processed = processed.replace(/^---$/gm, '<hr class=\"librebot-hr\">');\n\n // Blockquotes\n processed = processed.replace(/^&gt; (.+)$/gm, '<blockquote class=\"librebot-blockquote\">$1</blockquote>');\n\n // Convert newlines to <br> (but not inside lists/blockquotes)\n processed = processed.replace(/\\n/g, '<br>');\n\n // Clean up extra <br> after block elements\n processed = processed.replace(/<\\/(pre|ul|ol|blockquote|h[2-4])><br>/g, '</$1>');\n processed = processed.replace(/<br><(pre|ul|ol|blockquote|h[2-4])/g, '<$1');\n\n // Restore code blocks\n codeBlocks.forEach((block, i) => {\n processed = processed.replace(`%%CODEBLOCK${i}%%`, block);\n });\n\n // Restore inline code\n inlineCodes.forEach((code, i) => {\n processed = processed.replace(`%%INLINECODE${i}%%`, code);\n });\n\n return processed;\n }\n\n private showTyping(): HTMLDivElement {\n const typing = document.createElement('div');\n typing.className = 'librebot-typing';\n typing.innerHTML = '<span></span><span></span><span></span>';\n this.messagesContainer?.appendChild(typing);\n this.scrollToBottom();\n return typing;\n }\n\n private scrollToBottom(): void {\n if (this.messagesContainer) {\n this.messagesContainer.scrollTop = this.messagesContainer.scrollHeight;\n }\n }\n\n private async sendMessage(): Promise<void> {\n if (!this.input || this.isLoading) return;\n\n const content = this.input.value.trim();\n if (!content) return;\n\n // Add user message\n this.addMessage('user', content);\n this.input.value = '';\n\n // Show typing indicator\n this.isLoading = true;\n const typing = this.showTyping();\n\n try {\n if (this.config.streaming) {\n await this.callStreamingAPI(content, typing);\n } else {\n const response = await this.callAPI(content);\n typing.remove();\n\n if (response.error) {\n this.addMessage('assistant', `Sorry, I encountered an error: ${response.error}`);\n } else {\n this.addMessage('assistant', response.response);\n }\n }\n } catch (error) {\n typing.remove();\n this.addMessage('assistant', 'Sorry, I had trouble connecting. Please try again.');\n console.error('LibreBot error:', error);\n } finally {\n this.isLoading = false;\n }\n }\n\n private async callStreamingAPI(message: string, typing: HTMLDivElement): Promise<void> {\n const response = await fetch(`${this.config.apiUrl}/chat`, {\n method: 'POST',\n headers: {\n 'Content-Type': 'application/json',\n Authorization: `Bearer ${this.config.apiKey}`,\n },\n body: JSON.stringify({\n message,\n context: this.getConversationContext(),\n stream: true,\n sessionId: this.sessionId,\n }),\n });\n\n if (!response.ok) {\n typing.remove();\n const error = await response.json().catch(() => ({ error: 'Request failed' }));\n this.addMessage('assistant', `Sorry, I encountered an error: ${error.error || 'Request failed'}`);\n return;\n }\n\n // Remove typing indicator and create streaming message element\n typing.remove();\n const messageEl = document.createElement('div');\n messageEl.className = 'librebot-message assistant';\n this.messagesContainer?.appendChild(messageEl);\n\n const reader = response.body?.getReader();\n if (!reader) {\n this.addMessage('assistant', 'Sorry, streaming is not supported.');\n return;\n }\n\n const decoder = new TextDecoder();\n let fullContent = '';\n\n try {\n while (true) {\n const { done, value } = await reader.read();\n if (done) break;\n\n const chunk = decoder.decode(value, { stream: true });\n const lines = chunk.split('\\n').filter((line) => line.trim() !== '');\n\n for (const line of lines) {\n if (line.startsWith('data: ')) {\n const data = line.slice(6);\n if (data === '[DONE]') continue;\n\n try {\n const parsed = JSON.parse(data);\n if (parsed.content) {\n fullContent += parsed.content;\n messageEl.innerHTML = this.formatMessage(fullContent);\n this.scrollToBottom();\n }\n // Save sessionId when received from server\n if (parsed.sessionId) {\n this.saveSession(parsed.sessionId);\n }\n } catch {\n // Skip malformed JSON\n }\n }\n }\n }\n } catch (error) {\n console.error('Stream reading error:', error);\n }\n\n // Add to messages array\n this.messages.push({\n id: `msg-${Date.now()}`,\n role: 'assistant',\n content: fullContent,\n timestamp: new Date(),\n });\n }\n\n private async callAPI(message: string): Promise<ChatResponse> {\n const response = await fetch(`${this.config.apiUrl}/chat`, {\n method: 'POST',\n headers: {\n 'Content-Type': 'application/json',\n Authorization: `Bearer ${this.config.apiKey}`,\n },\n body: JSON.stringify({\n message,\n context: this.getConversationContext(),\n sessionId: this.sessionId,\n }),\n });\n\n if (!response.ok) {\n const error = await response.json().catch(() => ({ error: 'Request failed' }));\n return { response: '', error: error.error || 'Request failed' };\n }\n\n const data = await response.json();\n // Save sessionId when received from server\n if (data.sessionId) {\n this.saveSession(data.sessionId);\n }\n return data;\n }\n\n private getConversationContext(): Array<{ role: string; content: string }> {\n // Get last 10 messages for context\n return this.messages.slice(-10).map((m) => ({\n role: m.role,\n content: m.content,\n }));\n }\n\n public destroy(): void {\n this.container?.remove();\n document.getElementById('librebot-styles')?.remove();\n }\n\n public clearSession(): void {\n try {\n this.sessionId = null;\n this.messages = [];\n localStorage.removeItem(this.getSessionKey());\n if (this.messagesContainer) {\n this.messagesContainer.innerHTML = '';\n }\n // Re-add welcome message\n if (this.config.welcomeMessage) {\n this.addMessage('assistant', this.config.welcomeMessage);\n }\n } catch {\n // localStorage may not be available\n }\n }\n}\n","import { LibreBotWidget } from './widget';\nimport { LibreBotConfig } from './types';\n\n// Auto-initialize from script tag\n(function () {\n // Find the script tag - document.currentScript may be null with defer\n const script = document.currentScript as HTMLScriptElement\n || document.querySelector('script[data-key][src*=\"librebot\"]') as HTMLScriptElement;\n\n if (!script) {\n console.warn('LibreBot: Could not find script tag');\n return;\n }\n\n // Get config from data attributes\n const config: LibreBotConfig = {\n apiKey: script.dataset.key || script.dataset.apiKey || '',\n apiUrl: script.dataset.apiUrl || 'https://api.librebot.io',\n position: (script.dataset.position as 'bottom-right' | 'bottom-left') || 'bottom-right',\n theme: (script.dataset.theme as 'light' | 'dark' | 'auto') || 'dark',\n primaryColor: script.dataset.color || '#14b8a6',\n title: script.dataset.title || 'Libre Bot',\n subtitle: script.dataset.subtitle || 'AI Documentation Assistant',\n placeholder: script.dataset.placeholder || 'Ask a question...',\n welcomeMessage: script.dataset.welcome || 'Hi! I can help you find answers in the documentation. What would you like to know?',\n streaming: script.dataset.streaming !== 'false', // default true\n };\n\n if (!config.apiKey) {\n console.error('LibreBot: Missing data-key attribute');\n return;\n }\n\n // Initialize when DOM is ready\n if (document.readyState === 'loading') {\n document.addEventListener('DOMContentLoaded', () => {\n (window as any).LibreBot = new LibreBotWidget(config);\n });\n } else {\n (window as any).LibreBot = new LibreBotWidget(config);\n }\n})();\n\n// Export for manual initialization\nexport { LibreBotWidget, LibreBotConfig };\n"],"names":["chatIcon","LibreBotWidget","constructor","config","this","container","modal","messagesContainer","input","isOpen","messages","isLoading","sessionId","defaultConfig","apiUrl","position","theme","primaryColor","title","subtitle","placeholder","welcomeMessage","streaming","whiteLabel","autoLoadConfig","apiKey","loadRemoteConfig","then","init","console","error","response","fetch","ok","remoteConfig","json","getProvidedConfig","warn","provided","userConfig","defaults","loadSession","injectStyles","createWidget","addMessage","getSessionKey","stored","localStorage","getItem","saveSession","setItem","styleId","document","getElementById","style","createElement","id","textContent","getStyles","head","appendChild","className","fab","innerHTML","onclick","toggle","getModalHTML","body","querySelector","closeBtn","addEventListener","close","sendBtn","sendMessage","e","key","shiftKey","preventDefault","mediaQuery","window","matchMedia","updateTheme","matches","poweredByHtml","isLight","classList","add","remove","open","focus","role","content","message","Date","now","timestamp","push","renderMessage","el","formatMessage","scrollToBottom","escapeHtml","text","replace","codeBlocks","processed","_","lang","code","escaped","trim","langClass","length","inlineCodes","match","forEach","block","i","showTyping","typing","scrollTop","scrollHeight","value","callStreamingAPI","callAPI","method","headers","Authorization","JSON","stringify","context","getConversationContext","stream","catch","messageEl","reader","getReader","decoder","TextDecoder","fullContent","done","read","lines","decode","split","filter","line","startsWith","data","slice","parsed","parse","map","m","destroy","clearSession","removeItem","script","currentScript","dataset","color","welcome","readyState","LibreBot"],"mappings":"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"}
package/dist/types.d.ts CHANGED
@@ -20,6 +20,7 @@ export interface Message {
20
20
  }
21
21
  export interface ChatResponse {
22
22
  response: string;
23
+ sessionId?: string;
23
24
  usage?: {
24
25
  prompt_tokens: number;
25
26
  completion_tokens: number;
package/dist/widget.d.ts CHANGED
@@ -8,11 +8,15 @@ export declare class LibreBotWidget {
8
8
  private isOpen;
9
9
  private messages;
10
10
  private isLoading;
11
+ private sessionId;
11
12
  private defaultConfig;
12
13
  constructor(config: LibreBotConfig);
13
14
  private loadRemoteConfig;
14
15
  private getProvidedConfig;
15
16
  private init;
17
+ private getSessionKey;
18
+ private loadSession;
19
+ private saveSession;
16
20
  private injectStyles;
17
21
  private createWidget;
18
22
  private getModalHTML;
@@ -30,4 +34,5 @@ export declare class LibreBotWidget {
30
34
  private callAPI;
31
35
  private getConversationContext;
32
36
  destroy(): void;
37
+ clearSession(): void;
33
38
  }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@kroonen-ai/librebot-widget",
3
- "version": "1.1.1",
3
+ "version": "1.2.0",
4
4
  "type": "module",
5
5
  "description": "Libre Bot - AI documentation assistant widget",
6
6
  "main": "dist/librebot.js",