open-chat-studio-widget 0.8.0 → 0.9.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +1 -0
- package/dist/cjs/{index-Cf6K60f1.js → index-fFSp-Z_h.js} +3 -3
- package/dist/cjs/{index-Cf6K60f1.js.map → index-fFSp-Z_h.js.map} +1 -1
- package/dist/cjs/loader.cjs.js +2 -2
- package/dist/cjs/open-chat-studio-widget.cjs.entry.js +179 -24
- package/dist/cjs/open-chat-studio-widget.cjs.entry.js.map +1 -1
- package/dist/cjs/open-chat-studio-widget.cjs.js +2 -2
- package/dist/cjs/open-chat-studio-widget.entry.cjs.js.map +1 -1
- package/dist/collection/components/ocs-chat/ocs-chat.js +82 -4
- package/dist/collection/components/ocs-chat/ocs-chat.js.map +1 -1
- package/dist/collection/services/chat-session-service.js +95 -20
- package/dist/collection/services/chat-session-service.js.map +1 -1
- package/dist/collection/services/file-attachment-manager.js +3 -0
- package/dist/collection/services/file-attachment-manager.js.map +1 -1
- package/dist/components/open-chat-studio-widget.js +179 -23
- package/dist/components/open-chat-studio-widget.js.map +1 -1
- package/dist/esm/{index-DXf2dIht.js → index-ythTKHg-.js} +3 -3
- package/dist/esm/{index-DXf2dIht.js.map → index-ythTKHg-.js.map} +1 -1
- package/dist/esm/loader.js +3 -3
- package/dist/esm/open-chat-studio-widget.entry.js +179 -24
- package/dist/esm/open-chat-studio-widget.entry.js.map +1 -1
- package/dist/esm/open-chat-studio-widget.js +3 -3
- package/dist/open-chat-studio-widget/open-chat-studio-widget.entry.esm.js.map +1 -1
- package/dist/open-chat-studio-widget/open-chat-studio-widget.esm.js +1 -1
- package/dist/open-chat-studio-widget/p-2d31a15c.entry.js +4 -0
- package/dist/open-chat-studio-widget/p-2d31a15c.entry.js.map +1 -0
- package/dist/open-chat-studio-widget/{p-DXf2dIht.js → p-ythTKHg-.js} +2 -2
- package/dist/open-chat-studio-widget/{p-DXf2dIht.js.map → p-ythTKHg-.js.map} +1 -1
- package/dist/types/components/ocs-chat/ocs-chat.d.ts +14 -0
- package/dist/types/components.d.ts +8 -0
- package/dist/types/services/chat-session-service.d.ts +23 -0
- package/dist/types/services/file-attachment-manager.d.ts +3 -0
- package/package.json +1 -1
- package/dist/open-chat-studio-widget/p-ff47dabf.entry.js +0 -4
- package/dist/open-chat-studio-widget/p-ff47dabf.entry.js.map +0 -1
package/dist/cjs/loader.cjs.js
CHANGED
|
@@ -1,12 +1,12 @@
|
|
|
1
1
|
'use strict';
|
|
2
2
|
|
|
3
|
-
var index = require('./index-
|
|
3
|
+
var index = require('./index-fFSp-Z_h.js');
|
|
4
4
|
var appGlobals = require('./app-globals-V2Kpy_OQ.js');
|
|
5
5
|
|
|
6
6
|
const defineCustomElements = async (win, options) => {
|
|
7
7
|
if (typeof window === 'undefined') return undefined;
|
|
8
8
|
await appGlobals.globalScripts();
|
|
9
|
-
return index.bootstrapLazy([["open-chat-studio-widget.cjs",[[257,"open-chat-studio-widget",{"chatbotId":[1,"chatbot-id"],"apiBaseUrl":[1,"api-base-url"],"buttonText":[1,"button-text"],"iconUrl":[1,"icon-url"],"embedKey":[1,"embed-key"],"buttonShape":[1,"button-shape"],"showButton":[4,"show-button"],"mode":[1],"headerText":[1,"header-text"],"newChatConfirmationMessage":[1,"new-chat-confirmation-message"],"visible":[1028],"position":[1025],"welcomeMessages":[1,"welcome-messages"],"starterQuestions":[1,"starter-questions"],"userId":[1,"user-id"],"userName":[1,"user-name"],"persistentSession":[4,"persistent-session"],"persistentSessionExpire":[2,"persistent-session-expire"],"allowFullScreen":[4,"allow-full-screen"],"allowAttachments":[4,"allow-attachments"],"typingIndicatorText":[1,"typing-indicator-text"],"language":[1],"translationsUrl":[1,"translations-url"],"pageContext":[1040,"page-context"],"versionNumber":[2,"version-number"],"sessionId":[1,"session-id"],"error":[32],"messages":[32],"activeSessionId":[32],"isLoading":[32],"isTyping":[32],"typingProgressMessage":[32],"messageInput":[32],"currentPollTaskId":[32],"isDragging":[32],"dragOffset":[32],"windowPosition":[32],"fullscreenPosition":[32],"parsedWelcomeMessages":[32],"parsedStarterQuestions":[32],"generatedUserId":[32],"isFullscreen":[32],"showNewChatConfirmation":[32],"selectedFiles":[32],"isUploadingFiles":[32],"isButtonDragging":[32],"buttonWasDragged":[32]},null,{"pageContext":["pageContextHandler"],"chatbotId":["chatbotConfigHandler"],"versionNumber":["chatbotConfigHandler"],"visible":["visibilityHandler"]}]]]], options);
|
|
9
|
+
return index.bootstrapLazy([["open-chat-studio-widget.cjs",[[257,"open-chat-studio-widget",{"chatbotId":[1,"chatbot-id"],"apiBaseUrl":[1,"api-base-url"],"buttonText":[1,"button-text"],"iconUrl":[1,"icon-url"],"embedKey":[1,"embed-key"],"buttonShape":[1,"button-shape"],"showButton":[4,"show-button"],"mode":[1],"headerText":[1,"header-text"],"newChatConfirmationMessage":[1,"new-chat-confirmation-message"],"visible":[1028],"position":[1025],"welcomeMessages":[1,"welcome-messages"],"starterQuestions":[1,"starter-questions"],"userId":[1,"user-id"],"userName":[1,"user-name"],"persistentSession":[4,"persistent-session"],"persistentSessionExpire":[2,"persistent-session-expire"],"allowFullScreen":[4,"allow-full-screen"],"allowAttachments":[4,"allow-attachments"],"typingIndicatorText":[1,"typing-indicator-text"],"language":[1],"translationsUrl":[1,"translations-url"],"pageContext":[1040,"page-context"],"versionNumber":[2,"version-number"],"sessionId":[1,"session-id"],"sessionToken":[1,"session-token"],"error":[32],"messages":[32],"activeSessionId":[32],"isLoading":[32],"isTyping":[32],"typingProgressMessage":[32],"messageInput":[32],"currentPollTaskId":[32],"isDragging":[32],"dragOffset":[32],"windowPosition":[32],"fullscreenPosition":[32],"parsedWelcomeMessages":[32],"parsedStarterQuestions":[32],"generatedUserId":[32],"isFullscreen":[32],"showNewChatConfirmation":[32],"selectedFiles":[32],"isUploadingFiles":[32],"isButtonDragging":[32],"buttonWasDragged":[32]},null,{"pageContext":["pageContextHandler"],"chatbotId":["chatbotConfigHandler"],"versionNumber":["chatbotConfigHandler"],"visible":["visibilityHandler"]}]]]], options);
|
|
10
10
|
};
|
|
11
11
|
|
|
12
12
|
exports.setNonce = index.setNonce;
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
'use strict';
|
|
2
2
|
|
|
3
|
-
var index = require('./index-
|
|
3
|
+
var index = require('./index-fFSp-Z_h.js');
|
|
4
4
|
|
|
5
5
|
// eslint-disable-next-line @typescript-eslint/no-unused-vars
|
|
6
6
|
const OcsWidgetAvatar = () => {
|
|
@@ -4470,6 +4470,8 @@ var ar = {
|
|
|
4470
4470
|
"status.starting": "جارٍ بدء المحادثة...",
|
|
4471
4471
|
"status.typing": "جارٍ تحضير الرد",
|
|
4472
4472
|
"status.uploading": "جارٍ التحميل",
|
|
4473
|
+
"status.sessionExpired": "انتهت صلاحية جلسة الدردشة. سيتم بدء محادثة جديدة — يُرجى إعادة إرسال رسالتك.",
|
|
4474
|
+
"status.sessionError": "لم تعد جلسة الدردشة هذه متاحة.",
|
|
4473
4475
|
"modal.newChatTitle": "بدء محادثة جديدة",
|
|
4474
4476
|
"modal.newChatBody": "بدء محادثة جديدة سيؤدي إلى مسح المحادثة الحالية. هل ترغب بالمتابعة؟",
|
|
4475
4477
|
"modal.cancel": "إلغاء",
|
|
@@ -4502,6 +4504,8 @@ var en = {
|
|
|
4502
4504
|
"status.starting": "Starting chat...",
|
|
4503
4505
|
"status.typing": "Preparing response",
|
|
4504
4506
|
"status.uploading": "Uploading",
|
|
4507
|
+
"status.sessionExpired": "Your chat session expired. Starting a new chat — please resend your message.",
|
|
4508
|
+
"status.sessionError": "This chat session is no longer available.",
|
|
4505
4509
|
"modal.newChatTitle": "Start New Chat",
|
|
4506
4510
|
"modal.newChatBody": "Starting a new chat will clear your current conversation. Continue?",
|
|
4507
4511
|
"modal.cancel": "Cancel",
|
|
@@ -4534,6 +4538,8 @@ var es = {
|
|
|
4534
4538
|
"status.starting": "Iniciando chat...",
|
|
4535
4539
|
"status.typing": "Preparando respuesta",
|
|
4536
4540
|
"status.uploading": "Subiendo",
|
|
4541
|
+
"status.sessionExpired": "Tu sesión de chat ha expirado. Se iniciará un nuevo chat: vuelve a enviar tu mensaje.",
|
|
4542
|
+
"status.sessionError": "Esta sesión de chat ya no está disponible.",
|
|
4537
4543
|
"modal.newChatTitle": "Iniciar Nuevo Chat",
|
|
4538
4544
|
"modal.newChatBody": "Iniciar un nuevo chat borrará tu conversación actual. ¿Continuar?",
|
|
4539
4545
|
"modal.cancel": "Cancelar",
|
|
@@ -4566,6 +4572,8 @@ var fr = {
|
|
|
4566
4572
|
"status.starting": "Démarrage du chat...",
|
|
4567
4573
|
"status.typing": "Préparation de la réponse",
|
|
4568
4574
|
"status.uploading": "Téléversement",
|
|
4575
|
+
"status.sessionExpired": "Votre session de chat a expiré. Un nouveau chat va démarrer — veuillez renvoyer votre message.",
|
|
4576
|
+
"status.sessionError": "Cette session de chat n'est plus disponible.",
|
|
4569
4577
|
"modal.newChatTitle": "Nouveau Chat",
|
|
4570
4578
|
"modal.newChatBody": "Démarrer un nouveau chat effacera votre conversation actuelle. Continuer?",
|
|
4571
4579
|
"modal.cancel": "Annuler",
|
|
@@ -4598,6 +4606,8 @@ var hi = {
|
|
|
4598
4606
|
"status.starting": "चैट शुरू हो रही है...",
|
|
4599
4607
|
"status.typing": "जवाब तैयार किया जा रहा है",
|
|
4600
4608
|
"status.uploading": "अपलोड हो रहा है",
|
|
4609
|
+
"status.sessionExpired": "आपका चैट सत्र समाप्त हो गया है। एक नई चैट शुरू हो रही है — कृपया अपना संदेश फिर से भेजें।",
|
|
4610
|
+
"status.sessionError": "यह चैट सत्र अब उपलब्ध नहीं है।",
|
|
4601
4611
|
"modal.newChatTitle": "नई चैट शुरू करें",
|
|
4602
4612
|
"modal.newChatBody": "नई चैट शुरू करने से आपकी मौजूदा बातचीत हट जाएगी। क्या आप जारी रखना चाहते हैं?",
|
|
4603
4613
|
"modal.cancel": "रद्द करें",
|
|
@@ -4630,6 +4640,8 @@ var it = {
|
|
|
4630
4640
|
"status.starting": "Avvio della chat...",
|
|
4631
4641
|
"status.typing": "Preparazione della risposta",
|
|
4632
4642
|
"status.uploading": "Caricamento",
|
|
4643
|
+
"status.sessionExpired": "La tua sessione di chat è scaduta. Verrà avviata una nuova chat: invia di nuovo il tuo messaggio.",
|
|
4644
|
+
"status.sessionError": "Questa sessione di chat non è più disponibile.",
|
|
4633
4645
|
"modal.newChatTitle": "Avvia nuova chat",
|
|
4634
4646
|
"modal.newChatBody": "Avviare una nuova chat cancellerà la conversazione attuale. Continuare?",
|
|
4635
4647
|
"modal.cancel": "Annulla",
|
|
@@ -4662,6 +4674,8 @@ var pt = {
|
|
|
4662
4674
|
"status.starting": "Iniciando chat...",
|
|
4663
4675
|
"status.typing": "Preparando resposta",
|
|
4664
4676
|
"status.uploading": "Carregando",
|
|
4677
|
+
"status.sessionExpired": "Sua sessão de chat expirou. Iniciando um novo chat — reenvie sua mensagem.",
|
|
4678
|
+
"status.sessionError": "Esta sessão de chat não está mais disponível.",
|
|
4665
4679
|
"modal.newChatTitle": "Iniciar novo chat",
|
|
4666
4680
|
"modal.newChatBody": "Iniciar um novo chat apagará sua conversa atual. Deseja continuar?",
|
|
4667
4681
|
"modal.cancel": "Cancelar",
|
|
@@ -4694,6 +4708,8 @@ var sw = {
|
|
|
4694
4708
|
"status.starting": "Inaanzisha gumzo...",
|
|
4695
4709
|
"status.typing": "Inatayarisha jibu",
|
|
4696
4710
|
"status.uploading": "Inapakia",
|
|
4711
|
+
"status.sessionExpired": "Kipindi chako cha gumzo kimeisha. Gumzo jipya linaanza — tafadhali tuma tena ujumbe wako.",
|
|
4712
|
+
"status.sessionError": "Kipindi hiki cha gumzo hakipatikani tena.",
|
|
4697
4713
|
"modal.newChatTitle": "Anza gumzo jipya",
|
|
4698
4714
|
"modal.newChatBody": "Kuanza gumzo jipya kutafuta gumzo lako la sasa. Je, ungependa kuendelea?",
|
|
4699
4715
|
"modal.cancel": "Ghairi",
|
|
@@ -4726,6 +4742,8 @@ var uk = {
|
|
|
4726
4742
|
"status.starting": "Запуск чату...",
|
|
4727
4743
|
"status.typing": "Готується відповідь",
|
|
4728
4744
|
"status.uploading": "Завантаження",
|
|
4745
|
+
"status.sessionExpired": "Ваш сеанс чату завершився. Розпочинається новий чат — будь ласка, надішліть повідомлення ще раз.",
|
|
4746
|
+
"status.sessionError": "Цей сеанс чату більше недоступний.",
|
|
4729
4747
|
"modal.newChatTitle": "Почати новий чат",
|
|
4730
4748
|
"modal.newChatBody": "Початок нового чату видалить вашу поточну розмову. Продовжити?",
|
|
4731
4749
|
"modal.cancel": "Скасувати",
|
|
@@ -4982,55 +5000,54 @@ function currentDomainMatchesApiBaseUrl(apiBaseUrl) {
|
|
|
4982
5000
|
return window.location.origin === apiBase.origin;
|
|
4983
5001
|
}
|
|
4984
5002
|
|
|
5003
|
+
class SessionAccessError extends Error {
|
|
5004
|
+
constructor(status, code, message) {
|
|
5005
|
+
super(message);
|
|
5006
|
+
this.name = 'SessionAccessError';
|
|
5007
|
+
this.status = status;
|
|
5008
|
+
this.code = code;
|
|
5009
|
+
}
|
|
5010
|
+
}
|
|
4985
5011
|
class ChatSessionService {
|
|
4986
5012
|
constructor(options) {
|
|
4987
5013
|
var _a, _b, _c, _d;
|
|
4988
5014
|
this.apiBaseUrl = options.apiBaseUrl;
|
|
4989
5015
|
this.embedKey = options.embedKey;
|
|
4990
5016
|
this.widgetVersion = options.widgetVersion;
|
|
5017
|
+
this.sessionToken = options.sessionToken;
|
|
4991
5018
|
this.csrfTokenProvider = (_a = options.csrfTokenProvider) !== null && _a !== void 0 ? _a : getCSRFToken;
|
|
4992
5019
|
this.taskPollingIntervalMs = (_b = options.taskPollingIntervalMs) !== null && _b !== void 0 ? _b : 1000;
|
|
4993
5020
|
this.taskPollingMaxAttempts = (_c = options.taskPollingMaxAttempts) !== null && _c !== void 0 ? _c : 120;
|
|
4994
5021
|
this.messagePollingIntervalMs = (_d = options.messagePollingIntervalMs) !== null && _d !== void 0 ? _d : 30000;
|
|
4995
5022
|
}
|
|
4996
5023
|
async startSession(requestBody) {
|
|
4997
|
-
const response = await
|
|
5024
|
+
const response = await this.request(`${this.apiBaseUrl}/api/chat/start/`, {
|
|
4998
5025
|
method: 'POST',
|
|
4999
5026
|
headers: this.getJsonHeaders(),
|
|
5000
5027
|
body: JSON.stringify(requestBody),
|
|
5001
5028
|
});
|
|
5002
5029
|
if (!response.ok) {
|
|
5003
|
-
|
|
5030
|
+
await this.raiseForStatus(response, 'Failed to start session');
|
|
5004
5031
|
}
|
|
5005
5032
|
return response.json();
|
|
5006
5033
|
}
|
|
5007
5034
|
async sendMessage(sessionId, payload) {
|
|
5008
|
-
const response = await
|
|
5035
|
+
const response = await this.request(`${this.apiBaseUrl}/api/chat/${sessionId}/message/`, {
|
|
5009
5036
|
method: 'POST',
|
|
5010
5037
|
headers: this.getJsonHeaders(),
|
|
5011
5038
|
body: JSON.stringify(payload),
|
|
5012
5039
|
});
|
|
5013
5040
|
if (!response.ok) {
|
|
5014
|
-
|
|
5041
|
+
await this.raiseForStatus(response, 'Failed to send message');
|
|
5015
5042
|
}
|
|
5016
5043
|
return response.json();
|
|
5017
5044
|
}
|
|
5018
5045
|
async pollTaskOnce(sessionId, taskId) {
|
|
5019
|
-
const response = await
|
|
5046
|
+
const response = await this.request(`${this.apiBaseUrl}/api/chat/${sessionId}/${taskId}/poll/`, {
|
|
5020
5047
|
headers: this.getCommonHeaders(),
|
|
5021
5048
|
});
|
|
5022
5049
|
if (!response.ok) {
|
|
5023
|
-
|
|
5024
|
-
try {
|
|
5025
|
-
const data = (await response.json());
|
|
5026
|
-
if (data === null || data === void 0 ? void 0 : data.error) {
|
|
5027
|
-
errorMessage = data.error;
|
|
5028
|
-
}
|
|
5029
|
-
}
|
|
5030
|
-
catch (_a) {
|
|
5031
|
-
// non-JSON body; keep statusText fallback
|
|
5032
|
-
}
|
|
5033
|
-
throw new Error(errorMessage);
|
|
5050
|
+
await this.raiseForStatus(response, 'Failed to poll task');
|
|
5034
5051
|
}
|
|
5035
5052
|
return response.json();
|
|
5036
5053
|
}
|
|
@@ -5090,11 +5107,11 @@ class ChatSessionService {
|
|
|
5090
5107
|
if (since) {
|
|
5091
5108
|
url.searchParams.set('since', since);
|
|
5092
5109
|
}
|
|
5093
|
-
const response = await
|
|
5110
|
+
const response = await this.request(url.toString(), {
|
|
5094
5111
|
headers: this.getCommonHeaders(),
|
|
5095
5112
|
});
|
|
5096
5113
|
if (!response.ok) {
|
|
5097
|
-
|
|
5114
|
+
await this.raiseForStatus(response, 'Failed to poll messages');
|
|
5098
5115
|
}
|
|
5099
5116
|
return response.json();
|
|
5100
5117
|
}
|
|
@@ -5151,15 +5168,88 @@ class ChatSessionService {
|
|
|
5151
5168
|
this.messagePollingTimer = undefined;
|
|
5152
5169
|
}
|
|
5153
5170
|
}
|
|
5154
|
-
|
|
5171
|
+
setSessionToken(token) {
|
|
5172
|
+
this.sessionToken = token;
|
|
5173
|
+
}
|
|
5174
|
+
async request(input, init) {
|
|
5175
|
+
const response = await fetch(input, init);
|
|
5176
|
+
this.checkSunsetHeaders(response);
|
|
5177
|
+
return response;
|
|
5178
|
+
}
|
|
5179
|
+
/**
|
|
5180
|
+
* Log a deprecation warning (RFC 8594 `Deprecation`/`Sunset`/`Link` headers)
|
|
5181
|
+
* when the server reports that this widget version is deprecated. Warns
|
|
5182
|
+
* during the deprecation window and errors once the sunset date has passed.
|
|
5183
|
+
* Logs at most once per level so polling does not flood the console.
|
|
5184
|
+
*/
|
|
5185
|
+
checkSunsetHeaders(response) {
|
|
5186
|
+
const headers = response === null || response === void 0 ? void 0 : response.headers;
|
|
5187
|
+
if (!headers || typeof headers.get !== 'function') {
|
|
5188
|
+
return;
|
|
5189
|
+
}
|
|
5190
|
+
if (headers.get('Deprecation') !== 'true') {
|
|
5191
|
+
return;
|
|
5192
|
+
}
|
|
5193
|
+
const sunsetAt = this.parseSunsetDate(headers.get('Sunset'));
|
|
5194
|
+
const pastSunset = sunsetAt !== null && Date.now() >= sunsetAt.getTime();
|
|
5195
|
+
const level = pastSunset ? 'error' : 'warn';
|
|
5196
|
+
if (this.loggedSunsetLevel === level) {
|
|
5197
|
+
return;
|
|
5198
|
+
}
|
|
5199
|
+
this.loggedSunsetLevel = level;
|
|
5200
|
+
const upgradeUrl = this.parseSuccessorUrl(headers.get('Link'));
|
|
5201
|
+
const upgradeSuffix = upgradeUrl ? ` Upgrade: ${upgradeUrl}` : '';
|
|
5202
|
+
const sunsetText = sunsetAt ? sunsetAt.toUTCString() : 'an upcoming date';
|
|
5203
|
+
if (level === 'error') {
|
|
5204
|
+
console.error(`[open-chat-studio-widget] Widget version ${this.widgetVersion} is past its sunset date ` + `(${sunsetText}) and may stop working.${upgradeSuffix}`);
|
|
5205
|
+
}
|
|
5206
|
+
else {
|
|
5207
|
+
console.warn(`[open-chat-studio-widget] Widget version ${this.widgetVersion} is deprecated and will stop ` + `working after ${sunsetText}.${upgradeSuffix}`);
|
|
5208
|
+
}
|
|
5209
|
+
}
|
|
5210
|
+
parseSunsetDate(sunset) {
|
|
5211
|
+
if (!sunset) {
|
|
5212
|
+
return null;
|
|
5213
|
+
}
|
|
5214
|
+
const parsed = new Date(sunset);
|
|
5215
|
+
return Number.isNaN(parsed.getTime()) ? null : parsed;
|
|
5216
|
+
}
|
|
5217
|
+
parseSuccessorUrl(link) {
|
|
5218
|
+
const match = link === null || link === void 0 ? void 0 : link.match(/<([^>]+)>\s*;\s*rel="?successor-version"?/);
|
|
5219
|
+
return match === null || match === void 0 ? void 0 : match[1];
|
|
5220
|
+
}
|
|
5221
|
+
async raiseForStatus(response, fallbackPrefix) {
|
|
5222
|
+
let message = `${fallbackPrefix}: ${response.statusText}`;
|
|
5223
|
+
let code;
|
|
5224
|
+
try {
|
|
5225
|
+
const data = (await response.json());
|
|
5226
|
+
if (data === null || data === void 0 ? void 0 : data.error) {
|
|
5227
|
+
message = data.error;
|
|
5228
|
+
}
|
|
5229
|
+
code = data === null || data === void 0 ? void 0 : data.code;
|
|
5230
|
+
}
|
|
5231
|
+
catch (_a) {
|
|
5232
|
+
// non-JSON body; keep statusText fallback
|
|
5233
|
+
}
|
|
5234
|
+
if (response.status === 403) {
|
|
5235
|
+
throw new SessionAccessError(response.status, code, message);
|
|
5236
|
+
}
|
|
5237
|
+
throw new Error(message);
|
|
5238
|
+
}
|
|
5239
|
+
/** Headers for multipart requests (no Content-Type — fetch sets the boundary). */
|
|
5240
|
+
getUploadHeaders() {
|
|
5155
5241
|
const headers = this.getCommonHeaders();
|
|
5156
|
-
headers['Content-Type'] = 'application/json';
|
|
5157
5242
|
const csrfToken = this.csrfTokenProvider(this.apiBaseUrl);
|
|
5158
5243
|
if (csrfToken) {
|
|
5159
5244
|
headers['X-CSRFToken'] = csrfToken;
|
|
5160
5245
|
}
|
|
5161
5246
|
return headers;
|
|
5162
5247
|
}
|
|
5248
|
+
getJsonHeaders() {
|
|
5249
|
+
const headers = this.getUploadHeaders();
|
|
5250
|
+
headers['Content-Type'] = 'application/json';
|
|
5251
|
+
return headers;
|
|
5252
|
+
}
|
|
5163
5253
|
getCommonHeaders() {
|
|
5164
5254
|
const headers = {
|
|
5165
5255
|
'x-ocs-widget-version': this.widgetVersion,
|
|
@@ -5167,6 +5257,9 @@ class ChatSessionService {
|
|
|
5167
5257
|
if (this.embedKey) {
|
|
5168
5258
|
headers['X-Embed-Key'] = this.embedKey;
|
|
5169
5259
|
}
|
|
5260
|
+
if (this.sessionToken) {
|
|
5261
|
+
headers['X-Session-Token'] = this.sessionToken;
|
|
5262
|
+
}
|
|
5170
5263
|
return headers;
|
|
5171
5264
|
}
|
|
5172
5265
|
}
|
|
@@ -5216,6 +5309,7 @@ class FileAttachmentManager {
|
|
|
5216
5309
|
});
|
|
5217
5310
|
}
|
|
5218
5311
|
async uploadPendingFiles(existingFiles, context) {
|
|
5312
|
+
var _a;
|
|
5219
5313
|
if (existingFiles.length === 0) {
|
|
5220
5314
|
return { selectedFiles: existingFiles, uploadedIds: [] };
|
|
5221
5315
|
}
|
|
@@ -5235,6 +5329,7 @@ class FileAttachmentManager {
|
|
|
5235
5329
|
try {
|
|
5236
5330
|
const response = await fetch(`${context.apiBaseUrl}/api/chat/${context.sessionId}/upload/`, {
|
|
5237
5331
|
method: 'POST',
|
|
5332
|
+
headers: (_a = context.headers) !== null && _a !== void 0 ? _a : {},
|
|
5238
5333
|
body: formData,
|
|
5239
5334
|
});
|
|
5240
5335
|
if (!response.ok) {
|
|
@@ -5244,6 +5339,7 @@ class FileAttachmentManager {
|
|
|
5244
5339
|
selectedFiles: this.markPendingFilesWithError(existingFiles, errorMessage),
|
|
5245
5340
|
uploadedIds,
|
|
5246
5341
|
errorMessage,
|
|
5342
|
+
tokenRejected: response.status === 403,
|
|
5247
5343
|
};
|
|
5248
5344
|
}
|
|
5249
5345
|
const data = await this.safeJson(response);
|
|
@@ -5529,13 +5625,15 @@ const OcsChat = class {
|
|
|
5529
5625
|
if (this.isSessionBound()) {
|
|
5530
5626
|
// Bound to an externally-managed session: the host page is the source of truth.
|
|
5531
5627
|
this.activeSessionId = this.sessionId;
|
|
5628
|
+
this.applySessionToken(this.sessionToken);
|
|
5532
5629
|
}
|
|
5533
5630
|
else if (this.persistentSession && this.isLocalStorageAvailable()) {
|
|
5534
5631
|
// Always try to load existing session if localStorage is available
|
|
5535
|
-
const { sessionId, messages } = this.loadSessionFromStorage();
|
|
5632
|
+
const { sessionId, messages, sessionToken } = this.loadSessionFromStorage();
|
|
5536
5633
|
if (sessionId && messages) {
|
|
5537
5634
|
this.activeSessionId = sessionId;
|
|
5538
5635
|
this.messages = messages;
|
|
5636
|
+
this.applySessionToken(sessionToken);
|
|
5539
5637
|
}
|
|
5540
5638
|
}
|
|
5541
5639
|
this.parseWelcomeMessages();
|
|
@@ -5584,6 +5682,11 @@ const OcsChat = class {
|
|
|
5584
5682
|
this.removeButtonEventListeners();
|
|
5585
5683
|
window.removeEventListener('resize', this.handleWindowResize);
|
|
5586
5684
|
}
|
|
5685
|
+
applySessionToken(token) {
|
|
5686
|
+
var _a;
|
|
5687
|
+
this.currentSessionToken = token;
|
|
5688
|
+
(_a = this.chatService) === null || _a === void 0 ? void 0 : _a.setSessionToken(token);
|
|
5689
|
+
}
|
|
5587
5690
|
getChatService() {
|
|
5588
5691
|
if (!this.chatService) {
|
|
5589
5692
|
this.chatService = new ChatSessionService({
|
|
@@ -5593,6 +5696,7 @@ const OcsChat = class {
|
|
|
5593
5696
|
taskPollingIntervalMs: OcsChat.TASK_POLLING_INTERVAL_MS,
|
|
5594
5697
|
taskPollingMaxAttempts: OcsChat.TASK_POLLING_MAX_ATTEMPTS,
|
|
5595
5698
|
messagePollingIntervalMs: OcsChat.MESSAGE_POLLING_INTERVAL_MS,
|
|
5699
|
+
sessionToken: this.currentSessionToken,
|
|
5596
5700
|
});
|
|
5597
5701
|
}
|
|
5598
5702
|
return this.chatService;
|
|
@@ -5608,6 +5712,27 @@ const OcsChat = class {
|
|
|
5608
5712
|
this.saveSessionToStorage();
|
|
5609
5713
|
this.scrollToBottom();
|
|
5610
5714
|
}
|
|
5715
|
+
/**
|
|
5716
|
+
* Recover from a rejected session token (403). Unbound widgets discard the
|
|
5717
|
+
* dead session/token, show a notice, and start fresh on the next send; bound
|
|
5718
|
+
* widgets cannot restart a host-owned session, so they surface an error.
|
|
5719
|
+
*/
|
|
5720
|
+
handleSessionAccessError() {
|
|
5721
|
+
this.cleanup();
|
|
5722
|
+
this.isLoading = false;
|
|
5723
|
+
this.isTyping = false;
|
|
5724
|
+
this.isUploadingFiles = false;
|
|
5725
|
+
this.typingProgressMessage = '';
|
|
5726
|
+
if (this.isSessionBound()) {
|
|
5727
|
+
this.addErrorMessage(this.translationManager.get('status.sessionError', 'This chat session is no longer available.'));
|
|
5728
|
+
return;
|
|
5729
|
+
}
|
|
5730
|
+
this.sessionEpoch += 1;
|
|
5731
|
+
this.activeSessionId = undefined;
|
|
5732
|
+
this.applySessionToken(undefined);
|
|
5733
|
+
this.clearSessionStorage();
|
|
5734
|
+
this.addErrorMessage(this.translationManager.get('status.sessionExpired', 'Your chat session expired. Starting a new chat — please resend your message.'));
|
|
5735
|
+
}
|
|
5611
5736
|
handleError(errorText) {
|
|
5612
5737
|
// show as system message
|
|
5613
5738
|
this.addErrorMessage(errorText);
|
|
@@ -5680,12 +5805,14 @@ const OcsChat = class {
|
|
|
5680
5805
|
this.currentPollTaskId = '';
|
|
5681
5806
|
}
|
|
5682
5807
|
async startSession() {
|
|
5808
|
+
var _a;
|
|
5683
5809
|
const epoch = this.sessionEpoch;
|
|
5684
5810
|
try {
|
|
5685
5811
|
this.isLoading = true;
|
|
5686
5812
|
const userId = this.getOrGenerateUserId();
|
|
5687
5813
|
const requestBody = {
|
|
5688
5814
|
chatbot_id: this.chatbotId,
|
|
5815
|
+
use_session_token: true,
|
|
5689
5816
|
session_data: {
|
|
5690
5817
|
source: 'widget',
|
|
5691
5818
|
page_url: window.location.href,
|
|
@@ -5702,6 +5829,7 @@ const OcsChat = class {
|
|
|
5702
5829
|
if (epoch !== this.sessionEpoch)
|
|
5703
5830
|
return;
|
|
5704
5831
|
this.activeSessionId = data.session_id;
|
|
5832
|
+
this.applySessionToken((_a = data.session_token) !== null && _a !== void 0 ? _a : undefined);
|
|
5705
5833
|
this.saveSessionToStorage();
|
|
5706
5834
|
this.startMessagePolling();
|
|
5707
5835
|
}
|
|
@@ -5734,6 +5862,10 @@ const OcsChat = class {
|
|
|
5734
5862
|
catch (error) {
|
|
5735
5863
|
if (epoch !== this.sessionEpoch)
|
|
5736
5864
|
return;
|
|
5865
|
+
if (error instanceof SessionAccessError) {
|
|
5866
|
+
this.handleSessionAccessError();
|
|
5867
|
+
return;
|
|
5868
|
+
}
|
|
5737
5869
|
console.warn('Failed to load chat history:', error);
|
|
5738
5870
|
}
|
|
5739
5871
|
this.startMessagePolling();
|
|
@@ -5749,8 +5881,12 @@ const OcsChat = class {
|
|
|
5749
5881
|
sessionId: this.activeSessionId,
|
|
5750
5882
|
participantId: this.getOrGenerateUserId(),
|
|
5751
5883
|
participantName: this.userName,
|
|
5884
|
+
headers: this.getChatService().getUploadHeaders(),
|
|
5752
5885
|
});
|
|
5753
5886
|
this.selectedFiles = uploadResult.selectedFiles;
|
|
5887
|
+
if (uploadResult.tokenRejected) {
|
|
5888
|
+
throw new SessionAccessError(403, 'session_token_required', uploadResult.errorMessage || 'Session token rejected');
|
|
5889
|
+
}
|
|
5754
5890
|
return uploadResult.uploadedIds;
|
|
5755
5891
|
}
|
|
5756
5892
|
finally {
|
|
@@ -5842,6 +5978,10 @@ const OcsChat = class {
|
|
|
5842
5978
|
catch (error) {
|
|
5843
5979
|
if (epoch !== this.sessionEpoch)
|
|
5844
5980
|
return;
|
|
5981
|
+
if (error instanceof SessionAccessError) {
|
|
5982
|
+
this.handleSessionAccessError();
|
|
5983
|
+
return;
|
|
5984
|
+
}
|
|
5845
5985
|
const errorText = error instanceof Error ? error.message : 'Failed to send message';
|
|
5846
5986
|
this.handleError(errorText);
|
|
5847
5987
|
}
|
|
@@ -6016,8 +6156,12 @@ const OcsChat = class {
|
|
|
6016
6156
|
},
|
|
6017
6157
|
onError: error => {
|
|
6018
6158
|
this.typingProgressMessage = '';
|
|
6019
|
-
this.handleError(error.message);
|
|
6020
6159
|
this.taskPollingHandle = undefined;
|
|
6160
|
+
if (error instanceof SessionAccessError) {
|
|
6161
|
+
this.handleSessionAccessError();
|
|
6162
|
+
return;
|
|
6163
|
+
}
|
|
6164
|
+
this.handleError(error.message);
|
|
6021
6165
|
this.startMessagePolling();
|
|
6022
6166
|
},
|
|
6023
6167
|
});
|
|
@@ -6379,6 +6523,7 @@ const OcsChat = class {
|
|
|
6379
6523
|
messages: `ocs-chat-messages-${this.chatbotId}`,
|
|
6380
6524
|
lastActivity: `ocs-chat-activity-${this.chatbotId}`,
|
|
6381
6525
|
visible: `ocs-chat-visible-${this.chatbotId}`,
|
|
6526
|
+
sessionToken: `ocs-chat-token-${this.chatbotId}`,
|
|
6382
6527
|
};
|
|
6383
6528
|
}
|
|
6384
6529
|
saveSessionToStorage() {
|
|
@@ -6390,6 +6535,12 @@ const OcsChat = class {
|
|
|
6390
6535
|
if (this.activeSessionId) {
|
|
6391
6536
|
localStorage.setItem(keys.sessionId, this.activeSessionId);
|
|
6392
6537
|
localStorage.setItem(keys.lastActivity, new Date().toISOString());
|
|
6538
|
+
if (this.currentSessionToken) {
|
|
6539
|
+
localStorage.setItem(keys.sessionToken, this.currentSessionToken);
|
|
6540
|
+
}
|
|
6541
|
+
else {
|
|
6542
|
+
localStorage.removeItem(keys.sessionToken);
|
|
6543
|
+
}
|
|
6393
6544
|
}
|
|
6394
6545
|
localStorage.setItem(keys.messages, JSON.stringify(this.messages));
|
|
6395
6546
|
}
|
|
@@ -6398,6 +6549,7 @@ const OcsChat = class {
|
|
|
6398
6549
|
}
|
|
6399
6550
|
}
|
|
6400
6551
|
loadSessionFromStorage() {
|
|
6552
|
+
var _a;
|
|
6401
6553
|
const keys = this.getStorageKeys();
|
|
6402
6554
|
try {
|
|
6403
6555
|
if (this.persistentSessionExpire > 0) {
|
|
@@ -6425,7 +6577,8 @@ const OcsChat = class {
|
|
|
6425
6577
|
messages = [];
|
|
6426
6578
|
}
|
|
6427
6579
|
}
|
|
6428
|
-
|
|
6580
|
+
const sessionToken = (_a = localStorage.getItem(keys.sessionToken)) !== null && _a !== void 0 ? _a : undefined;
|
|
6581
|
+
return { sessionId, messages, sessionToken };
|
|
6429
6582
|
}
|
|
6430
6583
|
catch (error) {
|
|
6431
6584
|
// fall back to starting a new session
|
|
@@ -6497,6 +6650,7 @@ const OcsChat = class {
|
|
|
6497
6650
|
localStorage.removeItem(keys.messages);
|
|
6498
6651
|
localStorage.removeItem(keys.lastActivity);
|
|
6499
6652
|
localStorage.removeItem(keys.visible);
|
|
6653
|
+
localStorage.removeItem(keys.sessionToken);
|
|
6500
6654
|
}
|
|
6501
6655
|
catch (error) {
|
|
6502
6656
|
console.warn('Failed to clear chat session from localStorage:', error);
|
|
@@ -6538,6 +6692,7 @@ const OcsChat = class {
|
|
|
6538
6692
|
// A session provided by the host page (session-id prop) cannot be cleared;
|
|
6539
6693
|
// stay bound to it. Unbound widgets start a new session on the next message.
|
|
6540
6694
|
this.activeSessionId = this.sessionId;
|
|
6695
|
+
this.applySessionToken(this.isSessionBound() ? this.sessionToken : undefined);
|
|
6541
6696
|
this.messages = [];
|
|
6542
6697
|
this.isTyping = false;
|
|
6543
6698
|
this.currentPollTaskId = '';
|