@kroonen-ai/librebot-widget 1.2.0 → 1.3.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/index.d.ts +2 -0
- package/dist/librebot.esm.js +183 -10
- package/dist/librebot.esm.js.map +1 -1
- package/dist/librebot.js +1 -1
- package/dist/librebot.js.map +1 -1
- package/dist/translations.d.ts +12 -0
- package/dist/types.d.ts +2 -0
- package/dist/widget.d.ts +2 -0
- package/package.json +1 -1
package/dist/index.d.ts
CHANGED
|
@@ -1,2 +1,4 @@
|
|
|
1
1
|
export { LibreBotWidget } from './widget';
|
|
2
2
|
export type { LibreBotConfig, Message, ChatResponse } from './types';
|
|
3
|
+
export type { SupportedLang, WidgetTranslations } from './translations';
|
|
4
|
+
export { WIDGET_TRANSLATIONS, RTL_LANGUAGES, detectLanguage } from './translations';
|
package/dist/librebot.esm.js
CHANGED
|
@@ -467,12 +467,166 @@ const getStyles = (primaryColor = '#14b8a6') => `
|
|
|
467
467
|
.librebot-powered a:hover {
|
|
468
468
|
text-decoration: underline;
|
|
469
469
|
}
|
|
470
|
+
|
|
471
|
+
/* RTL Support */
|
|
472
|
+
.librebot-widget.rtl {
|
|
473
|
+
direction: rtl;
|
|
474
|
+
text-align: right;
|
|
475
|
+
}
|
|
476
|
+
|
|
477
|
+
.librebot-widget.rtl .librebot-message.user {
|
|
478
|
+
align-self: flex-start;
|
|
479
|
+
border-bottom-right-radius: 16px;
|
|
480
|
+
border-bottom-left-radius: 4px;
|
|
481
|
+
}
|
|
482
|
+
|
|
483
|
+
.librebot-widget.rtl .librebot-message.assistant {
|
|
484
|
+
align-self: flex-end;
|
|
485
|
+
border-bottom-left-radius: 16px;
|
|
486
|
+
border-bottom-right-radius: 4px;
|
|
487
|
+
}
|
|
488
|
+
|
|
489
|
+
.librebot-widget.rtl .librebot-typing {
|
|
490
|
+
align-self: flex-end;
|
|
491
|
+
border-bottom-left-radius: 16px;
|
|
492
|
+
border-bottom-right-radius: 4px;
|
|
493
|
+
}
|
|
494
|
+
|
|
495
|
+
.librebot-widget.rtl .librebot-header-content {
|
|
496
|
+
flex-direction: row-reverse;
|
|
497
|
+
}
|
|
498
|
+
|
|
499
|
+
.librebot-widget.rtl .librebot-input {
|
|
500
|
+
text-align: right;
|
|
501
|
+
}
|
|
502
|
+
|
|
503
|
+
.librebot-widget.rtl .librebot-input-area {
|
|
504
|
+
flex-direction: row-reverse;
|
|
505
|
+
}
|
|
506
|
+
|
|
507
|
+
.librebot-widget.rtl .librebot-ul,
|
|
508
|
+
.librebot-widget.rtl .librebot-ol {
|
|
509
|
+
padding-left: 0;
|
|
510
|
+
padding-right: 20px;
|
|
511
|
+
}
|
|
512
|
+
|
|
513
|
+
.librebot-widget.rtl .librebot-blockquote {
|
|
514
|
+
border-left: none;
|
|
515
|
+
border-right: 3px solid var(--lb-primary);
|
|
516
|
+
border-radius: 6px 0 0 6px;
|
|
517
|
+
}
|
|
470
518
|
`;
|
|
471
519
|
|
|
472
520
|
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>`;
|
|
473
521
|
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>`;
|
|
474
522
|
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>`;
|
|
475
523
|
|
|
524
|
+
const WIDGET_TRANSLATIONS = {
|
|
525
|
+
en: {
|
|
526
|
+
placeholder: 'Ask a question...',
|
|
527
|
+
welcomeMessage: 'Hi! I can help you find answers in the documentation. What would you like to know?',
|
|
528
|
+
errorPrefix: 'Sorry, I encountered an error:',
|
|
529
|
+
connectionError: 'Sorry, I had trouble connecting. Please try again.',
|
|
530
|
+
streamingNotSupported: 'Sorry, streaming is not supported.',
|
|
531
|
+
poweredBy: 'Powered by',
|
|
532
|
+
},
|
|
533
|
+
fr: {
|
|
534
|
+
placeholder: 'Posez une question...',
|
|
535
|
+
welcomeMessage: 'Bonjour ! Je peux vous aider à trouver des réponses dans la documentation. Que souhaitez-vous savoir ?',
|
|
536
|
+
errorPrefix: 'Désolé, j\'ai rencontré une erreur :',
|
|
537
|
+
connectionError: 'Désolé, j\'ai eu du mal à me connecter. Veuillez réessayer.',
|
|
538
|
+
streamingNotSupported: 'Désolé, le streaming n\'est pas pris en charge.',
|
|
539
|
+
poweredBy: 'Propulsé par',
|
|
540
|
+
},
|
|
541
|
+
de: {
|
|
542
|
+
placeholder: 'Stellen Sie eine Frage...',
|
|
543
|
+
welcomeMessage: 'Hallo! Ich kann Ihnen helfen, Antworten in der Dokumentation zu finden. Was möchten Sie wissen?',
|
|
544
|
+
errorPrefix: 'Entschuldigung, ein Fehler ist aufgetreten:',
|
|
545
|
+
connectionError: 'Entschuldigung, ich hatte Verbindungsprobleme. Bitte versuchen Sie es erneut.',
|
|
546
|
+
streamingNotSupported: 'Entschuldigung, Streaming wird nicht unterstützt.',
|
|
547
|
+
poweredBy: 'Betrieben von',
|
|
548
|
+
},
|
|
549
|
+
nl: {
|
|
550
|
+
placeholder: 'Stel een vraag...',
|
|
551
|
+
welcomeMessage: 'Hallo! Ik kan je helpen antwoorden te vinden in de documentatie. Wat wil je weten?',
|
|
552
|
+
errorPrefix: 'Sorry, er is een fout opgetreden:',
|
|
553
|
+
connectionError: 'Sorry, ik had moeite met verbinden. Probeer het opnieuw.',
|
|
554
|
+
streamingNotSupported: 'Sorry, streaming wordt niet ondersteund.',
|
|
555
|
+
poweredBy: 'Mogelijk gemaakt door',
|
|
556
|
+
},
|
|
557
|
+
es: {
|
|
558
|
+
placeholder: 'Haz una pregunta...',
|
|
559
|
+
welcomeMessage: '¡Hola! Puedo ayudarte a encontrar respuestas en la documentación. ¿Qué te gustaría saber?',
|
|
560
|
+
errorPrefix: 'Lo siento, encontré un error:',
|
|
561
|
+
connectionError: 'Lo siento, tuve problemas para conectarme. Por favor, inténtalo de nuevo.',
|
|
562
|
+
streamingNotSupported: 'Lo siento, el streaming no está soportado.',
|
|
563
|
+
poweredBy: 'Desarrollado por',
|
|
564
|
+
},
|
|
565
|
+
pt: {
|
|
566
|
+
placeholder: 'Faça uma pergunta...',
|
|
567
|
+
welcomeMessage: 'Olá! Posso ajudá-lo a encontrar respostas na documentação. O que você gostaria de saber?',
|
|
568
|
+
errorPrefix: 'Desculpe, encontrei um erro:',
|
|
569
|
+
connectionError: 'Desculpe, tive problemas para conectar. Por favor, tente novamente.',
|
|
570
|
+
streamingNotSupported: 'Desculpe, streaming não é suportado.',
|
|
571
|
+
poweredBy: 'Desenvolvido por',
|
|
572
|
+
},
|
|
573
|
+
ko: {
|
|
574
|
+
placeholder: '질문하세요...',
|
|
575
|
+
welcomeMessage: '안녕하세요! 문서에서 답변을 찾는 데 도움을 드릴 수 있습니다. 무엇을 알고 싶으신가요?',
|
|
576
|
+
errorPrefix: '죄송합니다. 오류가 발생했습니다:',
|
|
577
|
+
connectionError: '죄송합니다. 연결에 문제가 있습니다. 다시 시도해 주세요.',
|
|
578
|
+
streamingNotSupported: '죄송합니다. 스트리밍이 지원되지 않습니다.',
|
|
579
|
+
poweredBy: '제공:',
|
|
580
|
+
},
|
|
581
|
+
ja: {
|
|
582
|
+
placeholder: '質問してください...',
|
|
583
|
+
welcomeMessage: 'こんにちは!ドキュメントから回答を見つけるお手伝いができます。何をお知りになりたいですか?',
|
|
584
|
+
errorPrefix: '申し訳ありません。エラーが発生しました:',
|
|
585
|
+
connectionError: '申し訳ありません。接続に問題がありました。もう一度お試しください。',
|
|
586
|
+
streamingNotSupported: '申し訳ありません。ストリーミングはサポートされていません。',
|
|
587
|
+
poweredBy: '提供:',
|
|
588
|
+
},
|
|
589
|
+
zh: {
|
|
590
|
+
placeholder: '请提问...',
|
|
591
|
+
welcomeMessage: '您好!我可以帮助您在文档中查找答案。您想了解什么?',
|
|
592
|
+
errorPrefix: '抱歉,遇到了错误:',
|
|
593
|
+
connectionError: '抱歉,连接出现问题。请重试。',
|
|
594
|
+
streamingNotSupported: '抱歉,不支持流式传输。',
|
|
595
|
+
poweredBy: '由以下提供支持:',
|
|
596
|
+
},
|
|
597
|
+
hi: {
|
|
598
|
+
placeholder: 'कोई प्रश्न पूछें...',
|
|
599
|
+
welcomeMessage: 'नमस्ते! मैं आपको दस्तावेज़ों में उत्तर खोजने में मदद कर सकता हूं। आप क्या जानना चाहते हैं?',
|
|
600
|
+
errorPrefix: 'क्षमा करें, एक त्रुटि हुई:',
|
|
601
|
+
connectionError: 'क्षमा करें, कनेक्ट करने में समस्या हुई। कृपया पुनः प्रयास करें।',
|
|
602
|
+
streamingNotSupported: 'क्षमा करें, स्ट्रीमिंग समर्थित नहीं है।',
|
|
603
|
+
poweredBy: 'द्वारा संचालित',
|
|
604
|
+
},
|
|
605
|
+
ar: {
|
|
606
|
+
placeholder: 'اطرح سؤالاً...',
|
|
607
|
+
welcomeMessage: 'مرحباً! يمكنني مساعدتك في العثور على إجابات في الوثائق. ماذا تريد أن تعرف؟',
|
|
608
|
+
errorPrefix: 'عذراً، حدث خطأ:',
|
|
609
|
+
connectionError: 'عذراً، واجهت مشكلة في الاتصال. يرجى المحاولة مرة أخرى.',
|
|
610
|
+
streamingNotSupported: 'عذراً، البث غير مدعوم.',
|
|
611
|
+
poweredBy: 'مدعوم من',
|
|
612
|
+
},
|
|
613
|
+
};
|
|
614
|
+
const RTL_LANGUAGES = ['ar'];
|
|
615
|
+
function detectLanguage() {
|
|
616
|
+
// 1. Check document's lang attribute
|
|
617
|
+
const htmlLang = document.documentElement.lang?.toLowerCase().split('-')[0];
|
|
618
|
+
if (htmlLang && htmlLang in WIDGET_TRANSLATIONS) {
|
|
619
|
+
return htmlLang;
|
|
620
|
+
}
|
|
621
|
+
// 2. Check navigator.language
|
|
622
|
+
const navLang = navigator.language?.toLowerCase().split('-')[0];
|
|
623
|
+
if (navLang && navLang in WIDGET_TRANSLATIONS) {
|
|
624
|
+
return navLang;
|
|
625
|
+
}
|
|
626
|
+
// 3. Default to English
|
|
627
|
+
return 'en';
|
|
628
|
+
}
|
|
629
|
+
|
|
476
630
|
class LibreBotWidget {
|
|
477
631
|
constructor(config) {
|
|
478
632
|
this.container = null;
|
|
@@ -483,6 +637,8 @@ class LibreBotWidget {
|
|
|
483
637
|
this.messages = [];
|
|
484
638
|
this.isLoading = false;
|
|
485
639
|
this.sessionId = null;
|
|
640
|
+
this.translations = WIDGET_TRANSLATIONS.en;
|
|
641
|
+
this.isRtl = false;
|
|
486
642
|
this.defaultConfig = {
|
|
487
643
|
apiUrl: 'https://librebot.io/api',
|
|
488
644
|
position: 'bottom-right',
|
|
@@ -490,17 +646,29 @@ class LibreBotWidget {
|
|
|
490
646
|
primaryColor: '#14b8a6',
|
|
491
647
|
title: 'Libre Bot',
|
|
492
648
|
subtitle: 'AI Documentation Assistant',
|
|
493
|
-
placeholder: '
|
|
494
|
-
welcomeMessage: '
|
|
649
|
+
placeholder: '', // Will be set from translations
|
|
650
|
+
welcomeMessage: '', // Will be set from translations
|
|
495
651
|
streaming: true,
|
|
496
652
|
whiteLabel: false,
|
|
497
653
|
autoLoadConfig: true,
|
|
654
|
+
lang: 'en',
|
|
498
655
|
};
|
|
499
656
|
if (!config.apiKey) {
|
|
500
657
|
console.error('LibreBot: API key is required');
|
|
501
658
|
return;
|
|
502
659
|
}
|
|
503
|
-
|
|
660
|
+
// Detect language from config or host page
|
|
661
|
+
const detectedLang = config.lang || detectLanguage();
|
|
662
|
+
this.translations = WIDGET_TRANSLATIONS[detectedLang] || WIDGET_TRANSLATIONS.en;
|
|
663
|
+
this.isRtl = RTL_LANGUAGES.includes(detectedLang);
|
|
664
|
+
// Apply defaults with translations
|
|
665
|
+
const configWithTranslations = {
|
|
666
|
+
...config,
|
|
667
|
+
lang: detectedLang,
|
|
668
|
+
placeholder: config.placeholder || this.translations.placeholder,
|
|
669
|
+
welcomeMessage: config.welcomeMessage || this.translations.welcomeMessage,
|
|
670
|
+
};
|
|
671
|
+
this.config = { ...this.defaultConfig, ...configWithTranslations };
|
|
504
672
|
// Auto-load config from server if enabled and no custom settings provided
|
|
505
673
|
if (this.config.autoLoadConfig) {
|
|
506
674
|
this.loadRemoteConfig().then(() => this.init());
|
|
@@ -601,7 +769,12 @@ class LibreBotWidget {
|
|
|
601
769
|
createWidget() {
|
|
602
770
|
// Create container
|
|
603
771
|
this.container = document.createElement('div');
|
|
604
|
-
|
|
772
|
+
let className = 'librebot-widget';
|
|
773
|
+
if (this.config.theme === 'light')
|
|
774
|
+
className += ' light';
|
|
775
|
+
if (this.isRtl)
|
|
776
|
+
className += ' rtl';
|
|
777
|
+
this.container.className = className;
|
|
605
778
|
// Create FAB button
|
|
606
779
|
const fab = document.createElement('button');
|
|
607
780
|
fab.className = `librebot-fab ${this.config.position === 'bottom-left' ? 'left' : ''}`;
|
|
@@ -640,7 +813,7 @@ class LibreBotWidget {
|
|
|
640
813
|
const poweredByHtml = this.config.whiteLabel
|
|
641
814
|
? ''
|
|
642
815
|
: `<div class="librebot-powered">
|
|
643
|
-
|
|
816
|
+
${this.translations.poweredBy} <a href="https://librebot.io" target="_blank">Libre Bot</a>
|
|
644
817
|
</div>`;
|
|
645
818
|
return `
|
|
646
819
|
<div class="librebot-header">
|
|
@@ -800,7 +973,7 @@ class LibreBotWidget {
|
|
|
800
973
|
const response = await this.callAPI(content);
|
|
801
974
|
typing.remove();
|
|
802
975
|
if (response.error) {
|
|
803
|
-
this.addMessage('assistant',
|
|
976
|
+
this.addMessage('assistant', `${this.translations.errorPrefix} ${response.error}`);
|
|
804
977
|
}
|
|
805
978
|
else {
|
|
806
979
|
this.addMessage('assistant', response.response);
|
|
@@ -809,7 +982,7 @@ class LibreBotWidget {
|
|
|
809
982
|
}
|
|
810
983
|
catch (error) {
|
|
811
984
|
typing.remove();
|
|
812
|
-
this.addMessage('assistant',
|
|
985
|
+
this.addMessage('assistant', this.translations.connectionError);
|
|
813
986
|
console.error('LibreBot error:', error);
|
|
814
987
|
}
|
|
815
988
|
finally {
|
|
@@ -833,7 +1006,7 @@ class LibreBotWidget {
|
|
|
833
1006
|
if (!response.ok) {
|
|
834
1007
|
typing.remove();
|
|
835
1008
|
const error = await response.json().catch(() => ({ error: 'Request failed' }));
|
|
836
|
-
this.addMessage('assistant',
|
|
1009
|
+
this.addMessage('assistant', `${this.translations.errorPrefix} ${error.error || 'Request failed'}`);
|
|
837
1010
|
return;
|
|
838
1011
|
}
|
|
839
1012
|
// Remove typing indicator and create streaming message element
|
|
@@ -843,7 +1016,7 @@ class LibreBotWidget {
|
|
|
843
1016
|
this.messagesContainer?.appendChild(messageEl);
|
|
844
1017
|
const reader = response.body?.getReader();
|
|
845
1018
|
if (!reader) {
|
|
846
|
-
this.addMessage('assistant',
|
|
1019
|
+
this.addMessage('assistant', this.translations.streamingNotSupported);
|
|
847
1020
|
return;
|
|
848
1021
|
}
|
|
849
1022
|
const decoder = new TextDecoder();
|
|
@@ -944,5 +1117,5 @@ class LibreBotWidget {
|
|
|
944
1117
|
}
|
|
945
1118
|
}
|
|
946
1119
|
|
|
947
|
-
export { LibreBotWidget };
|
|
1120
|
+
export { LibreBotWidget, RTL_LANGUAGES, WIDGET_TRANSLATIONS, detectLanguage };
|
|
948
1121
|
//# sourceMappingURL=librebot.esm.js.map
|
package/dist/librebot.esm.js.map
CHANGED
|
@@ -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 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, '&')\n .replace(/</g, '<')\n .replace(/>/g, '>')\n .replace(/\"/g, '"')\n .replace(/'/g, ''');\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(/^> (.+)$/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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"}
|
|
1
|
+
{"version":3,"file":"librebot.esm.js","sources":["../src/styles.ts","../src/icons.ts","../src/translations.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 /* RTL Support */\n .librebot-widget.rtl {\n direction: rtl;\n text-align: right;\n }\n\n .librebot-widget.rtl .librebot-message.user {\n align-self: flex-start;\n border-bottom-right-radius: 16px;\n border-bottom-left-radius: 4px;\n }\n\n .librebot-widget.rtl .librebot-message.assistant {\n align-self: flex-end;\n border-bottom-left-radius: 16px;\n border-bottom-right-radius: 4px;\n }\n\n .librebot-widget.rtl .librebot-typing {\n align-self: flex-end;\n border-bottom-left-radius: 16px;\n border-bottom-right-radius: 4px;\n }\n\n .librebot-widget.rtl .librebot-header-content {\n flex-direction: row-reverse;\n }\n\n .librebot-widget.rtl .librebot-input {\n text-align: right;\n }\n\n .librebot-widget.rtl .librebot-input-area {\n flex-direction: row-reverse;\n }\n\n .librebot-widget.rtl .librebot-ul,\n .librebot-widget.rtl .librebot-ol {\n padding-left: 0;\n padding-right: 20px;\n }\n\n .librebot-widget.rtl .librebot-blockquote {\n border-left: none;\n border-right: 3px solid var(--lb-primary);\n border-radius: 6px 0 0 6px;\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","export type SupportedLang = 'en' | 'fr' | 'de' | 'nl' | 'es' | 'pt' | 'ko' | 'ja' | 'zh' | 'hi' | 'ar';\n\nexport interface WidgetTranslations {\n placeholder: string;\n welcomeMessage: string;\n errorPrefix: string;\n connectionError: string;\n streamingNotSupported: string;\n poweredBy: string;\n}\n\nexport const WIDGET_TRANSLATIONS: Record<SupportedLang, WidgetTranslations> = {\n en: {\n placeholder: 'Ask a question...',\n welcomeMessage: 'Hi! I can help you find answers in the documentation. What would you like to know?',\n errorPrefix: 'Sorry, I encountered an error:',\n connectionError: 'Sorry, I had trouble connecting. Please try again.',\n streamingNotSupported: 'Sorry, streaming is not supported.',\n poweredBy: 'Powered by',\n },\n fr: {\n placeholder: 'Posez une question...',\n welcomeMessage: 'Bonjour ! Je peux vous aider à trouver des réponses dans la documentation. Que souhaitez-vous savoir ?',\n errorPrefix: 'Désolé, j\\'ai rencontré une erreur :',\n connectionError: 'Désolé, j\\'ai eu du mal à me connecter. Veuillez réessayer.',\n streamingNotSupported: 'Désolé, le streaming n\\'est pas pris en charge.',\n poweredBy: 'Propulsé par',\n },\n de: {\n placeholder: 'Stellen Sie eine Frage...',\n welcomeMessage: 'Hallo! Ich kann Ihnen helfen, Antworten in der Dokumentation zu finden. Was möchten Sie wissen?',\n errorPrefix: 'Entschuldigung, ein Fehler ist aufgetreten:',\n connectionError: 'Entschuldigung, ich hatte Verbindungsprobleme. Bitte versuchen Sie es erneut.',\n streamingNotSupported: 'Entschuldigung, Streaming wird nicht unterstützt.',\n poweredBy: 'Betrieben von',\n },\n nl: {\n placeholder: 'Stel een vraag...',\n welcomeMessage: 'Hallo! Ik kan je helpen antwoorden te vinden in de documentatie. Wat wil je weten?',\n errorPrefix: 'Sorry, er is een fout opgetreden:',\n connectionError: 'Sorry, ik had moeite met verbinden. Probeer het opnieuw.',\n streamingNotSupported: 'Sorry, streaming wordt niet ondersteund.',\n poweredBy: 'Mogelijk gemaakt door',\n },\n es: {\n placeholder: 'Haz una pregunta...',\n welcomeMessage: '¡Hola! Puedo ayudarte a encontrar respuestas en la documentación. ¿Qué te gustaría saber?',\n errorPrefix: 'Lo siento, encontré un error:',\n connectionError: 'Lo siento, tuve problemas para conectarme. Por favor, inténtalo de nuevo.',\n streamingNotSupported: 'Lo siento, el streaming no está soportado.',\n poweredBy: 'Desarrollado por',\n },\n pt: {\n placeholder: 'Faça uma pergunta...',\n welcomeMessage: 'Olá! Posso ajudá-lo a encontrar respostas na documentação. O que você gostaria de saber?',\n errorPrefix: 'Desculpe, encontrei um erro:',\n connectionError: 'Desculpe, tive problemas para conectar. Por favor, tente novamente.',\n streamingNotSupported: 'Desculpe, streaming não é suportado.',\n poweredBy: 'Desenvolvido por',\n },\n ko: {\n placeholder: '질문하세요...',\n welcomeMessage: '안녕하세요! 문서에서 답변을 찾는 데 도움을 드릴 수 있습니다. 무엇을 알고 싶으신가요?',\n errorPrefix: '죄송합니다. 오류가 발생했습니다:',\n connectionError: '죄송합니다. 연결에 문제가 있습니다. 다시 시도해 주세요.',\n streamingNotSupported: '죄송합니다. 스트리밍이 지원되지 않습니다.',\n poweredBy: '제공:',\n },\n ja: {\n placeholder: '質問してください...',\n welcomeMessage: 'こんにちは!ドキュメントから回答を見つけるお手伝いができます。何をお知りになりたいですか?',\n errorPrefix: '申し訳ありません。エラーが発生しました:',\n connectionError: '申し訳ありません。接続に問題がありました。もう一度お試しください。',\n streamingNotSupported: '申し訳ありません。ストリーミングはサポートされていません。',\n poweredBy: '提供:',\n },\n zh: {\n placeholder: '请提问...',\n welcomeMessage: '您好!我可以帮助您在文档中查找答案。您想了解什么?',\n errorPrefix: '抱歉,遇到了错误:',\n connectionError: '抱歉,连接出现问题。请重试。',\n streamingNotSupported: '抱歉,不支持流式传输。',\n poweredBy: '由以下提供支持:',\n },\n hi: {\n placeholder: 'कोई प्रश्न पूछें...',\n welcomeMessage: 'नमस्ते! मैं आपको दस्तावेज़ों में उत्तर खोजने में मदद कर सकता हूं। आप क्या जानना चाहते हैं?',\n errorPrefix: 'क्षमा करें, एक त्रुटि हुई:',\n connectionError: 'क्षमा करें, कनेक्ट करने में समस्या हुई। कृपया पुनः प्रयास करें।',\n streamingNotSupported: 'क्षमा करें, स्ट्रीमिंग समर्थित नहीं है।',\n poweredBy: 'द्वारा संचालित',\n },\n ar: {\n placeholder: 'اطرح سؤالاً...',\n welcomeMessage: 'مرحباً! يمكنني مساعدتك في العثور على إجابات في الوثائق. ماذا تريد أن تعرف؟',\n errorPrefix: 'عذراً، حدث خطأ:',\n connectionError: 'عذراً، واجهت مشكلة في الاتصال. يرجى المحاولة مرة أخرى.',\n streamingNotSupported: 'عذراً، البث غير مدعوم.',\n poweredBy: 'مدعوم من',\n },\n};\n\nexport const RTL_LANGUAGES: SupportedLang[] = ['ar'];\n\nexport function detectLanguage(): SupportedLang {\n // 1. Check document's lang attribute\n const htmlLang = document.documentElement.lang?.toLowerCase().split('-')[0];\n if (htmlLang && htmlLang in WIDGET_TRANSLATIONS) {\n return htmlLang as SupportedLang;\n }\n\n // 2. Check navigator.language\n const navLang = navigator.language?.toLowerCase().split('-')[0];\n if (navLang && navLang in WIDGET_TRANSLATIONS) {\n return navLang as SupportedLang;\n }\n\n // 3. Default to English\n return 'en';\n}\n","import { LibreBotConfig, Message, ChatResponse } from './types';\nimport { getStyles } from './styles';\nimport { chatIcon, closeIcon, sendIcon } from './icons';\nimport {\n SupportedLang,\n WidgetTranslations,\n WIDGET_TRANSLATIONS,\n RTL_LANGUAGES,\n detectLanguage\n} from './translations';\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 private translations: WidgetTranslations = WIDGET_TRANSLATIONS.en;\n private isRtl = 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: '', // Will be set from translations\n welcomeMessage: '', // Will be set from translations\n streaming: true,\n whiteLabel: false,\n autoLoadConfig: true,\n lang: 'en',\n };\n\n constructor(config: LibreBotConfig) {\n if (!config.apiKey) {\n console.error('LibreBot: API key is required');\n return;\n }\n\n // Detect language from config or host page\n const detectedLang = config.lang || detectLanguage();\n this.translations = WIDGET_TRANSLATIONS[detectedLang] || WIDGET_TRANSLATIONS.en;\n this.isRtl = RTL_LANGUAGES.includes(detectedLang);\n\n // Apply defaults with translations\n const configWithTranslations: Partial<LibreBotConfig> = {\n ...config,\n lang: detectedLang,\n placeholder: config.placeholder || this.translations.placeholder,\n welcomeMessage: config.welcomeMessage || this.translations.welcomeMessage,\n };\n\n this.config = { ...this.defaultConfig, ...configWithTranslations } 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 let className = 'librebot-widget';\n if (this.config.theme === 'light') className += ' light';\n if (this.isRtl) className += ' rtl';\n this.container.className = className;\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 ${this.translations.poweredBy} <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, '&')\n .replace(/</g, '<')\n .replace(/>/g, '>')\n .replace(/\"/g, '"')\n .replace(/'/g, ''');\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(/^> (.+)$/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', `${this.translations.errorPrefix} ${response.error}`);\n } else {\n this.addMessage('assistant', response.response);\n }\n }\n } catch (error) {\n typing.remove();\n this.addMessage('assistant', this.translations.connectionError);\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', `${this.translations.errorPrefix} ${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', this.translations.streamingNotSupported);\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.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,"&").replace(/</g,"<").replace(/>/g,">").replace(/"/g,""").replace(/'/g,"'"),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(/^> (.+)$/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}({});
|
|
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>',t={en:{placeholder:"Ask a question...",welcomeMessage:"Hi! I can help you find answers in the documentation. What would you like to know?",errorPrefix:"Sorry, I encountered an error:",connectionError:"Sorry, I had trouble connecting. Please try again.",streamingNotSupported:"Sorry, streaming is not supported.",poweredBy:"Powered by"},fr:{placeholder:"Posez une question...",welcomeMessage:"Bonjour ! Je peux vous aider à trouver des réponses dans la documentation. Que souhaitez-vous savoir ?",errorPrefix:"Désolé, j'ai rencontré une erreur :",connectionError:"Désolé, j'ai eu du mal à me connecter. Veuillez réessayer.",streamingNotSupported:"Désolé, le streaming n'est pas pris en charge.",poweredBy:"Propulsé par"},de:{placeholder:"Stellen Sie eine Frage...",welcomeMessage:"Hallo! Ich kann Ihnen helfen, Antworten in der Dokumentation zu finden. Was möchten Sie wissen?",errorPrefix:"Entschuldigung, ein Fehler ist aufgetreten:",connectionError:"Entschuldigung, ich hatte Verbindungsprobleme. Bitte versuchen Sie es erneut.",streamingNotSupported:"Entschuldigung, Streaming wird nicht unterstützt.",poweredBy:"Betrieben von"},nl:{placeholder:"Stel een vraag...",welcomeMessage:"Hallo! Ik kan je helpen antwoorden te vinden in de documentatie. Wat wil je weten?",errorPrefix:"Sorry, er is een fout opgetreden:",connectionError:"Sorry, ik had moeite met verbinden. Probeer het opnieuw.",streamingNotSupported:"Sorry, streaming wordt niet ondersteund.",poweredBy:"Mogelijk gemaakt door"},es:{placeholder:"Haz una pregunta...",welcomeMessage:"¡Hola! Puedo ayudarte a encontrar respuestas en la documentación. ¿Qué te gustaría saber?",errorPrefix:"Lo siento, encontré un error:",connectionError:"Lo siento, tuve problemas para conectarme. Por favor, inténtalo de nuevo.",streamingNotSupported:"Lo siento, el streaming no está soportado.",poweredBy:"Desarrollado por"},pt:{placeholder:"Faça uma pergunta...",welcomeMessage:"Olá! Posso ajudá-lo a encontrar respostas na documentação. O que você gostaria de saber?",errorPrefix:"Desculpe, encontrei um erro:",connectionError:"Desculpe, tive problemas para conectar. Por favor, tente novamente.",streamingNotSupported:"Desculpe, streaming não é suportado.",poweredBy:"Desenvolvido por"},ko:{placeholder:"질문하세요...",welcomeMessage:"안녕하세요! 문서에서 답변을 찾는 데 도움을 드릴 수 있습니다. 무엇을 알고 싶으신가요?",errorPrefix:"죄송합니다. 오류가 발생했습니다:",connectionError:"죄송합니다. 연결에 문제가 있습니다. 다시 시도해 주세요.",streamingNotSupported:"죄송합니다. 스트리밍이 지원되지 않습니다.",poweredBy:"제공:"},ja:{placeholder:"質問してください...",welcomeMessage:"こんにちは!ドキュメントから回答を見つけるお手伝いができます。何をお知りになりたいですか?",errorPrefix:"申し訳ありません。エラーが発生しました:",connectionError:"申し訳ありません。接続に問題がありました。もう一度お試しください。",streamingNotSupported:"申し訳ありません。ストリーミングはサポートされていません。",poweredBy:"提供:"},zh:{placeholder:"请提问...",welcomeMessage:"您好!我可以帮助您在文档中查找答案。您想了解什么?",errorPrefix:"抱歉,遇到了错误:",connectionError:"抱歉,连接出现问题。请重试。",streamingNotSupported:"抱歉,不支持流式传输。",poweredBy:"由以下提供支持:"},hi:{placeholder:"कोई प्रश्न पूछें...",welcomeMessage:"नमस्ते! मैं आपको दस्तावेज़ों में उत्तर खोजने में मदद कर सकता हूं। आप क्या जानना चाहते हैं?",errorPrefix:"क्षमा करें, एक त्रुटि हुई:",connectionError:"क्षमा करें, कनेक्ट करने में समस्या हुई। कृपया पुनः प्रयास करें।",streamingNotSupported:"क्षमा करें, स्ट्रीमिंग समर्थित नहीं है।",poweredBy:"द्वारा संचालित"},ar:{placeholder:"اطرح سؤالاً...",welcomeMessage:"مرحباً! يمكنني مساعدتك في العثور على إجابات في الوثائق. ماذا تريد أن تعرف؟",errorPrefix:"عذراً، حدث خطأ:",connectionError:"عذراً، واجهت مشكلة في الاتصال. يرجى المحاولة مرة أخرى.",streamingNotSupported:"عذراً، البث غير مدعوم.",poweredBy:"مدعوم من"}},o=["ar"];class r{constructor(e){if(this.container=null,this.modal=null,this.messagesContainer=null,this.input=null,this.isOpen=!1,this.messages=[],this.isLoading=!1,this.sessionId=null,this.translations=t.en,this.isRtl=!1,this.defaultConfig={apiUrl:"https://librebot.io/api",position:"bottom-right",theme:"dark",primaryColor:"#14b8a6",title:"Libre Bot",subtitle:"AI Documentation Assistant",placeholder:"",welcomeMessage:"",streaming:!0,whiteLabel:!1,autoLoadConfig:!0,lang:"en"},!e.apiKey)return void console.error("LibreBot: API key is required");const n=e.lang||function(){const e=document.documentElement.lang?.toLowerCase().split("-")[0];if(e&&e in t)return e;const n=navigator.language?.toLowerCase().split("-")[0];return n&&n in t?n:"en"}();this.translations=t[n]||t.en,this.isRtl=o.includes(n);const r={...e,lang:n,placeholder:e.placeholder||this.translations.placeholder,welcomeMessage:e.welcomeMessage||this.translations.welcomeMessage};this.config={...this.defaultConfig,...r},this.config.autoLoadConfig?this.loadRemoteConfig().then(()=>this.init()):this.init()}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\n /* RTL Support */\n .librebot-widget.rtl {\n direction: rtl;\n text-align: right;\n }\n\n .librebot-widget.rtl .librebot-message.user {\n align-self: flex-start;\n border-bottom-right-radius: 16px;\n border-bottom-left-radius: 4px;\n }\n\n .librebot-widget.rtl .librebot-message.assistant {\n align-self: flex-end;\n border-bottom-left-radius: 16px;\n border-bottom-right-radius: 4px;\n }\n\n .librebot-widget.rtl .librebot-typing {\n align-self: flex-end;\n border-bottom-left-radius: 16px;\n border-bottom-right-radius: 4px;\n }\n\n .librebot-widget.rtl .librebot-header-content {\n flex-direction: row-reverse;\n }\n\n .librebot-widget.rtl .librebot-input {\n text-align: right;\n }\n\n .librebot-widget.rtl .librebot-input-area {\n flex-direction: row-reverse;\n }\n\n .librebot-widget.rtl .librebot-ul,\n .librebot-widget.rtl .librebot-ol {\n padding-left: 0;\n padding-right: 20px;\n }\n\n .librebot-widget.rtl .librebot-blockquote {\n border-left: none;\n border-right: 3px solid var(--lb-primary);\n border-radius: 6px 0 0 6px;\n }\n`)(this.config.primaryColor),document.head.appendChild(n)}createWidget(){this.container=document.createElement("div");let e="librebot-widget";"light"===this.config.theme&&(e+=" light"),this.isRtl&&(e+=" rtl"),this.container.className=e;const t=document.createElement("button");t.className="librebot-fab "+("bottom-left"===this.config.position?"left":""),t.innerHTML=n,t.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(t),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 o=this.modal.querySelector(".librebot-close");o?.addEventListener("click",()=>this.close());const r=this.modal.querySelector(".librebot-send");if(r?.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 ${this.translations.poweredBy} <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,"&").replace(/</g,"<").replace(/>/g,">").replace(/"/g,""").replace(/'/g,"'"),t=[];let o=e.replace(/```\s*(\w*)\s*\n?([\s\S]*?)```/g,(e,o,r)=>{const i=n(r.trim()),s=o?` data-language="${n(o)}"`:"";return t.push(`<pre class="librebot-code-block"${s}><code>${i}</code></pre>`),`%%CODEBLOCK${t.length-1}%%`});const r=[];return o=o.replace(/`([^`]+)`/g,(e,t)=>(r.push(`<code class="librebot-inline-code">${n(t)}</code>`),`%%INLINECODE${r.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(/^> (.+)$/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)}),r.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",`${this.translations.errorPrefix} ${t.error}`):this.addMessage("assistant",t.response)}}catch(e){n.remove(),this.addMessage("assistant",this.translations.connectionError),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",`${this.translations.errorPrefix} ${e.error||"Request failed"}`)}n.remove();const o=document.createElement("div");o.className="librebot-message assistant",this.messagesContainer?.appendChild(o);const r=t.body?.getReader();if(!r)return void this.addMessage("assistant",this.translations.streamingNotSupported);const i=new TextDecoder;let s="";try{for(;;){const{done:e,value:n}=await r.read();if(e)break;const t=i.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 async 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=e.dataset.key||e.dataset.apiKey||"",t=e.dataset.apiUrl||"https://api.librebot.io";if(!n)return void console.error("LibreBot: Missing data-key attribute");let o={};try{const e=await fetch(`${t}/api/widget-config?key=${encodeURIComponent(n)}`);e.ok&&(o=await e.json())}catch(e){}const i={apiKey:n,apiUrl:t,position:e.dataset.position||o.position||"bottom-right",theme:e.dataset.theme||o.theme||"dark",primaryColor:e.dataset.color||o.primaryColor||"#14b8a6",title:e.dataset.title||o.title||"Libre Bot",subtitle:e.dataset.subtitle||o.subtitle||"AI Documentation Assistant",placeholder:e.dataset.placeholder||o.placeholder||void 0,welcomeMessage:e.dataset.welcome||o.welcomeMessage||void 0,streaming:"false"!==e.dataset.streaming,whiteLabel:o.whiteLabel||!1,lang:e.dataset.lang||o.lang},s=()=>{window.LibreBot=new r(i)};"loading"===document.readyState?document.addEventListener("DOMContentLoaded",s):s()}(),e.LibreBotWidget=r,e}({});
|
|
2
2
|
//# sourceMappingURL=librebot.js.map
|
package/dist/librebot.js.map
CHANGED
|
@@ -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 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, '&')\n .replace(/</g, '<')\n .replace(/>/g, '>')\n .replace(/\"/g, '"')\n .replace(/'/g, ''');\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(/^> (.+)$/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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"}
|
|
1
|
+
{"version":3,"file":"librebot.js","sources":["../src/styles.ts","../src/icons.ts","../src/translations.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 /* RTL Support */\n .librebot-widget.rtl {\n direction: rtl;\n text-align: right;\n }\n\n .librebot-widget.rtl .librebot-message.user {\n align-self: flex-start;\n border-bottom-right-radius: 16px;\n border-bottom-left-radius: 4px;\n }\n\n .librebot-widget.rtl .librebot-message.assistant {\n align-self: flex-end;\n border-bottom-left-radius: 16px;\n border-bottom-right-radius: 4px;\n }\n\n .librebot-widget.rtl .librebot-typing {\n align-self: flex-end;\n border-bottom-left-radius: 16px;\n border-bottom-right-radius: 4px;\n }\n\n .librebot-widget.rtl .librebot-header-content {\n flex-direction: row-reverse;\n }\n\n .librebot-widget.rtl .librebot-input {\n text-align: right;\n }\n\n .librebot-widget.rtl .librebot-input-area {\n flex-direction: row-reverse;\n }\n\n .librebot-widget.rtl .librebot-ul,\n .librebot-widget.rtl .librebot-ol {\n padding-left: 0;\n padding-right: 20px;\n }\n\n .librebot-widget.rtl .librebot-blockquote {\n border-left: none;\n border-right: 3px solid var(--lb-primary);\n border-radius: 6px 0 0 6px;\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","export type SupportedLang = 'en' | 'fr' | 'de' | 'nl' | 'es' | 'pt' | 'ko' | 'ja' | 'zh' | 'hi' | 'ar';\n\nexport interface WidgetTranslations {\n placeholder: string;\n welcomeMessage: string;\n errorPrefix: string;\n connectionError: string;\n streamingNotSupported: string;\n poweredBy: string;\n}\n\nexport const WIDGET_TRANSLATIONS: Record<SupportedLang, WidgetTranslations> = {\n en: {\n placeholder: 'Ask a question...',\n welcomeMessage: 'Hi! I can help you find answers in the documentation. What would you like to know?',\n errorPrefix: 'Sorry, I encountered an error:',\n connectionError: 'Sorry, I had trouble connecting. Please try again.',\n streamingNotSupported: 'Sorry, streaming is not supported.',\n poweredBy: 'Powered by',\n },\n fr: {\n placeholder: 'Posez une question...',\n welcomeMessage: 'Bonjour ! Je peux vous aider à trouver des réponses dans la documentation. Que souhaitez-vous savoir ?',\n errorPrefix: 'Désolé, j\\'ai rencontré une erreur :',\n connectionError: 'Désolé, j\\'ai eu du mal à me connecter. Veuillez réessayer.',\n streamingNotSupported: 'Désolé, le streaming n\\'est pas pris en charge.',\n poweredBy: 'Propulsé par',\n },\n de: {\n placeholder: 'Stellen Sie eine Frage...',\n welcomeMessage: 'Hallo! Ich kann Ihnen helfen, Antworten in der Dokumentation zu finden. Was möchten Sie wissen?',\n errorPrefix: 'Entschuldigung, ein Fehler ist aufgetreten:',\n connectionError: 'Entschuldigung, ich hatte Verbindungsprobleme. Bitte versuchen Sie es erneut.',\n streamingNotSupported: 'Entschuldigung, Streaming wird nicht unterstützt.',\n poweredBy: 'Betrieben von',\n },\n nl: {\n placeholder: 'Stel een vraag...',\n welcomeMessage: 'Hallo! Ik kan je helpen antwoorden te vinden in de documentatie. Wat wil je weten?',\n errorPrefix: 'Sorry, er is een fout opgetreden:',\n connectionError: 'Sorry, ik had moeite met verbinden. Probeer het opnieuw.',\n streamingNotSupported: 'Sorry, streaming wordt niet ondersteund.',\n poweredBy: 'Mogelijk gemaakt door',\n },\n es: {\n placeholder: 'Haz una pregunta...',\n welcomeMessage: '¡Hola! Puedo ayudarte a encontrar respuestas en la documentación. ¿Qué te gustaría saber?',\n errorPrefix: 'Lo siento, encontré un error:',\n connectionError: 'Lo siento, tuve problemas para conectarme. Por favor, inténtalo de nuevo.',\n streamingNotSupported: 'Lo siento, el streaming no está soportado.',\n poweredBy: 'Desarrollado por',\n },\n pt: {\n placeholder: 'Faça uma pergunta...',\n welcomeMessage: 'Olá! Posso ajudá-lo a encontrar respostas na documentação. O que você gostaria de saber?',\n errorPrefix: 'Desculpe, encontrei um erro:',\n connectionError: 'Desculpe, tive problemas para conectar. Por favor, tente novamente.',\n streamingNotSupported: 'Desculpe, streaming não é suportado.',\n poweredBy: 'Desenvolvido por',\n },\n ko: {\n placeholder: '질문하세요...',\n welcomeMessage: '안녕하세요! 문서에서 답변을 찾는 데 도움을 드릴 수 있습니다. 무엇을 알고 싶으신가요?',\n errorPrefix: '죄송합니다. 오류가 발생했습니다:',\n connectionError: '죄송합니다. 연결에 문제가 있습니다. 다시 시도해 주세요.',\n streamingNotSupported: '죄송합니다. 스트리밍이 지원되지 않습니다.',\n poweredBy: '제공:',\n },\n ja: {\n placeholder: '質問してください...',\n welcomeMessage: 'こんにちは!ドキュメントから回答を見つけるお手伝いができます。何をお知りになりたいですか?',\n errorPrefix: '申し訳ありません。エラーが発生しました:',\n connectionError: '申し訳ありません。接続に問題がありました。もう一度お試しください。',\n streamingNotSupported: '申し訳ありません。ストリーミングはサポートされていません。',\n poweredBy: '提供:',\n },\n zh: {\n placeholder: '请提问...',\n welcomeMessage: '您好!我可以帮助您在文档中查找答案。您想了解什么?',\n errorPrefix: '抱歉,遇到了错误:',\n connectionError: '抱歉,连接出现问题。请重试。',\n streamingNotSupported: '抱歉,不支持流式传输。',\n poweredBy: '由以下提供支持:',\n },\n hi: {\n placeholder: 'कोई प्रश्न पूछें...',\n welcomeMessage: 'नमस्ते! मैं आपको दस्तावेज़ों में उत्तर खोजने में मदद कर सकता हूं। आप क्या जानना चाहते हैं?',\n errorPrefix: 'क्षमा करें, एक त्रुटि हुई:',\n connectionError: 'क्षमा करें, कनेक्ट करने में समस्या हुई। कृपया पुनः प्रयास करें।',\n streamingNotSupported: 'क्षमा करें, स्ट्रीमिंग समर्थित नहीं है।',\n poweredBy: 'द्वारा संचालित',\n },\n ar: {\n placeholder: 'اطرح سؤالاً...',\n welcomeMessage: 'مرحباً! يمكنني مساعدتك في العثور على إجابات في الوثائق. ماذا تريد أن تعرف؟',\n errorPrefix: 'عذراً، حدث خطأ:',\n connectionError: 'عذراً، واجهت مشكلة في الاتصال. يرجى المحاولة مرة أخرى.',\n streamingNotSupported: 'عذراً، البث غير مدعوم.',\n poweredBy: 'مدعوم من',\n },\n};\n\nexport const RTL_LANGUAGES: SupportedLang[] = ['ar'];\n\nexport function detectLanguage(): SupportedLang {\n // 1. Check document's lang attribute\n const htmlLang = document.documentElement.lang?.toLowerCase().split('-')[0];\n if (htmlLang && htmlLang in WIDGET_TRANSLATIONS) {\n return htmlLang as SupportedLang;\n }\n\n // 2. Check navigator.language\n const navLang = navigator.language?.toLowerCase().split('-')[0];\n if (navLang && navLang in WIDGET_TRANSLATIONS) {\n return navLang as SupportedLang;\n }\n\n // 3. Default to English\n return 'en';\n}\n","import { LibreBotConfig, Message, ChatResponse } from './types';\nimport { getStyles } from './styles';\nimport { chatIcon, closeIcon, sendIcon } from './icons';\nimport {\n SupportedLang,\n WidgetTranslations,\n WIDGET_TRANSLATIONS,\n RTL_LANGUAGES,\n detectLanguage\n} from './translations';\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 private translations: WidgetTranslations = WIDGET_TRANSLATIONS.en;\n private isRtl = 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: '', // Will be set from translations\n welcomeMessage: '', // Will be set from translations\n streaming: true,\n whiteLabel: false,\n autoLoadConfig: true,\n lang: 'en',\n };\n\n constructor(config: LibreBotConfig) {\n if (!config.apiKey) {\n console.error('LibreBot: API key is required');\n return;\n }\n\n // Detect language from config or host page\n const detectedLang = config.lang || detectLanguage();\n this.translations = WIDGET_TRANSLATIONS[detectedLang] || WIDGET_TRANSLATIONS.en;\n this.isRtl = RTL_LANGUAGES.includes(detectedLang);\n\n // Apply defaults with translations\n const configWithTranslations: Partial<LibreBotConfig> = {\n ...config,\n lang: detectedLang,\n placeholder: config.placeholder || this.translations.placeholder,\n welcomeMessage: config.welcomeMessage || this.translations.welcomeMessage,\n };\n\n this.config = { ...this.defaultConfig, ...configWithTranslations } 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 let className = 'librebot-widget';\n if (this.config.theme === 'light') className += ' light';\n if (this.isRtl) className += ' rtl';\n this.container.className = className;\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 ${this.translations.poweredBy} <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, '&')\n .replace(/</g, '<')\n .replace(/>/g, '>')\n .replace(/\"/g, '"')\n .replace(/'/g, ''');\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(/^> (.+)$/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', `${this.translations.errorPrefix} ${response.error}`);\n } else {\n this.addMessage('assistant', response.response);\n }\n }\n } catch (error) {\n typing.remove();\n this.addMessage('assistant', this.translations.connectionError);\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', `${this.translations.errorPrefix} ${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', this.translations.streamingNotSupported);\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';\nimport { SupportedLang } from './translations';\n\n// Auto-initialize from script tag\n(async 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 const apiKey = script.dataset.key || script.dataset.apiKey || '';\n const apiUrl = script.dataset.apiUrl || 'https://api.librebot.io';\n\n if (!apiKey) {\n console.error('LibreBot: Missing data-key attribute');\n return;\n }\n\n // Fetch remote config from dashboard settings\n let remoteConfig: Partial<LibreBotConfig> = {};\n try {\n const response = await fetch(`${apiUrl}/api/widget-config?key=${encodeURIComponent(apiKey)}`);\n if (response.ok) {\n remoteConfig = await response.json();\n }\n } catch (e) {\n // Silently fail - use defaults/data attributes\n }\n\n // Build config: remote settings as base, data attributes as overrides\n const config: LibreBotConfig = {\n apiKey,\n apiUrl,\n // Remote config as defaults, data attributes override\n position: (script.dataset.position as 'bottom-right' | 'bottom-left') || remoteConfig.position || 'bottom-right',\n theme: (script.dataset.theme as 'light' | 'dark' | 'auto') || remoteConfig.theme || 'dark',\n primaryColor: script.dataset.color || remoteConfig.primaryColor || '#14b8a6',\n title: script.dataset.title || remoteConfig.title || 'Libre Bot',\n subtitle: script.dataset.subtitle || remoteConfig.subtitle || 'AI Documentation Assistant',\n placeholder: script.dataset.placeholder || remoteConfig.placeholder || undefined, // Let language detection handle default\n welcomeMessage: script.dataset.welcome || remoteConfig.welcomeMessage || undefined, // Let language detection handle default\n streaming: script.dataset.streaming !== 'false', // default true\n whiteLabel: remoteConfig.whiteLabel || false,\n lang: (script.dataset.lang as SupportedLang) || remoteConfig.lang, // Allow explicit language override\n };\n\n // Initialize when DOM is ready\n const initWidget = () => {\n (window as any).LibreBot = new LibreBotWidget(config);\n };\n\n if (document.readyState === 'loading') {\n document.addEventListener('DOMContentLoaded', initWidget);\n } else {\n initWidget();\n }\n})();\n\n// Export for manual initialization\nexport { LibreBotWidget, LibreBotConfig };\n"],"names":["chatIcon","WIDGET_TRANSLATIONS","en","placeholder","welcomeMessage","errorPrefix","connectionError","streamingNotSupported","poweredBy","fr","de","nl","es","pt","ko","ja","zh","hi","ar","RTL_LANGUAGES","LibreBotWidget","constructor","config","this","container","modal","messagesContainer","input","isOpen","messages","isLoading","sessionId","translations","isRtl","defaultConfig","apiUrl","position","theme","primaryColor","title","subtitle","streaming","whiteLabel","autoLoadConfig","lang","apiKey","console","error","detectedLang","htmlLang","document","documentElement","toLowerCase","split","navLang","navigator","language","detectLanguage","includes","configWithTranslations","loadRemoteConfig","then","init","response","fetch","ok","remoteConfig","json","getProvidedConfig","warn","provided","userConfig","defaults","loadSession","injectStyles","createWidget","addMessage","getSessionKey","stored","localStorage","getItem","saveSession","setItem","styleId","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","_","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","filter","line","startsWith","data","slice","parsed","parse","map","m","destroy","clearSession","removeItem","script","currentScript","dataset","encodeURIComponent","color","undefined","welcome","initWidget","LibreBot","readyState"],"mappings":"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"}
|
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
export type SupportedLang = 'en' | 'fr' | 'de' | 'nl' | 'es' | 'pt' | 'ko' | 'ja' | 'zh' | 'hi' | 'ar';
|
|
2
|
+
export interface WidgetTranslations {
|
|
3
|
+
placeholder: string;
|
|
4
|
+
welcomeMessage: string;
|
|
5
|
+
errorPrefix: string;
|
|
6
|
+
connectionError: string;
|
|
7
|
+
streamingNotSupported: string;
|
|
8
|
+
poweredBy: string;
|
|
9
|
+
}
|
|
10
|
+
export declare const WIDGET_TRANSLATIONS: Record<SupportedLang, WidgetTranslations>;
|
|
11
|
+
export declare const RTL_LANGUAGES: SupportedLang[];
|
|
12
|
+
export declare function detectLanguage(): SupportedLang;
|
package/dist/types.d.ts
CHANGED
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
import type { SupportedLang } from './translations';
|
|
1
2
|
export interface LibreBotConfig {
|
|
2
3
|
apiKey: string;
|
|
3
4
|
apiUrl?: string;
|
|
@@ -11,6 +12,7 @@ export interface LibreBotConfig {
|
|
|
11
12
|
streaming?: boolean;
|
|
12
13
|
whiteLabel?: boolean;
|
|
13
14
|
autoLoadConfig?: boolean;
|
|
15
|
+
lang?: SupportedLang;
|
|
14
16
|
}
|
|
15
17
|
export interface Message {
|
|
16
18
|
id: string;
|
package/dist/widget.d.ts
CHANGED