open-chat-studio-widget 0.7.0 → 0.8.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.
Files changed (32) hide show
  1. package/README.md +27 -26
  2. package/dist/cjs/{index-CvB341El.js → index-Cf6K60f1.js} +3 -3
  3. package/dist/cjs/{index-CvB341El.js.map → index-Cf6K60f1.js.map} +1 -1
  4. package/dist/cjs/loader.cjs.js +2 -2
  5. package/dist/cjs/open-chat-studio-widget.cjs.entry.js +119 -39
  6. package/dist/cjs/open-chat-studio-widget.cjs.entry.js.map +1 -1
  7. package/dist/cjs/open-chat-studio-widget.cjs.js +2 -2
  8. package/dist/cjs/open-chat-studio-widget.entry.cjs.js.map +1 -1
  9. package/dist/collection/components/ocs-chat/ocs-chat.js +94 -25
  10. package/dist/collection/components/ocs-chat/ocs-chat.js.map +1 -1
  11. package/dist/collection/services/chat-session-service.js +35 -1
  12. package/dist/collection/services/chat-session-service.js.map +1 -1
  13. package/dist/components/open-chat-studio-widget.js +120 -39
  14. package/dist/components/open-chat-studio-widget.js.map +1 -1
  15. package/dist/esm/{index-C2QZK0Ui.js → index-DXf2dIht.js} +3 -3
  16. package/dist/esm/{index-C2QZK0Ui.js.map → index-DXf2dIht.js.map} +1 -1
  17. package/dist/esm/loader.js +3 -3
  18. package/dist/esm/open-chat-studio-widget.entry.js +119 -39
  19. package/dist/esm/open-chat-studio-widget.entry.js.map +1 -1
  20. package/dist/esm/open-chat-studio-widget.js +3 -3
  21. package/dist/open-chat-studio-widget/open-chat-studio-widget.entry.esm.js.map +1 -1
  22. package/dist/open-chat-studio-widget/open-chat-studio-widget.esm.js +1 -1
  23. package/dist/open-chat-studio-widget/{p-C2QZK0Ui.js → p-DXf2dIht.js} +2 -2
  24. package/dist/open-chat-studio-widget/{p-C2QZK0Ui.js.map → p-DXf2dIht.js.map} +1 -1
  25. package/dist/open-chat-studio-widget/p-ff47dabf.entry.js +4 -0
  26. package/dist/open-chat-studio-widget/p-ff47dabf.entry.js.map +1 -0
  27. package/dist/types/components/ocs-chat/ocs-chat.d.ts +15 -1
  28. package/dist/types/components.d.ts +10 -2
  29. package/dist/types/services/chat-session-service.d.ts +6 -0
  30. package/package.json +1 -1
  31. package/dist/open-chat-studio-widget/p-e87d4e31.entry.js +0 -4
  32. package/dist/open-chat-studio-widget/p-e87d4e31.entry.js.map +0 -1
@@ -38,6 +38,7 @@ export class OcsChat {
38
38
  this.position = 'right';
39
39
  /**
40
40
  * Whether to persist session data to local storage to allow resuming previous conversations after page reload.
41
+ * Ignored when `sessionId` is provided.
41
42
  */
42
43
  this.persistentSession = true;
43
44
  /**
@@ -233,11 +234,15 @@ export class OcsChat {
233
234
  this.visible = true;
234
235
  }
235
236
  await this.initializeTranslations();
236
- // Always try to load existing session if localStorage is available
237
- if (this.persistentSession && this.isLocalStorageAvailable()) {
237
+ if (this.isSessionBound()) {
238
+ // Bound to an externally-managed session: the host page is the source of truth.
239
+ this.activeSessionId = this.sessionId;
240
+ }
241
+ else if (this.persistentSession && this.isLocalStorageAvailable()) {
242
+ // Always try to load existing session if localStorage is available
238
243
  const { sessionId, messages } = this.loadSessionFromStorage();
239
244
  if (sessionId && messages) {
240
- this.sessionId = sessionId;
245
+ this.activeSessionId = sessionId;
241
246
  this.messages = messages;
242
247
  }
243
248
  }
@@ -270,8 +275,13 @@ export class OcsChat {
270
275
  }
271
276
  }
272
277
  // Resume polling for existing session (don't auto-start new sessions)
273
- if (this.visible && this.sessionId) {
274
- this.startMessagePolling();
278
+ if (this.visible && this.activeSessionId) {
279
+ if (this.isSessionBound()) {
280
+ void this.loadBoundSessionHistory();
281
+ }
282
+ else {
283
+ this.startMessagePolling();
284
+ }
275
285
  }
276
286
  }, 0);
277
287
  window.addEventListener('resize', this.handleWindowResize);
@@ -399,7 +409,7 @@ export class OcsChat {
399
409
  const data = await this.getChatService().startSession(requestBody);
400
410
  if (epoch !== this.sessionEpoch)
401
411
  return;
402
- this.sessionId = data.session_id;
412
+ this.activeSessionId = data.session_id;
403
413
  this.saveSessionToStorage();
404
414
  this.startMessagePolling();
405
415
  }
@@ -412,15 +422,39 @@ export class OcsChat {
412
422
  this.isLoading = false;
413
423
  }
414
424
  }
425
+ /**
426
+ * Load the full message history for a session provided via the `session-id`
427
+ * prop, then begin regular polling.
428
+ */
429
+ async loadBoundSessionHistory() {
430
+ const epoch = this.sessionEpoch;
431
+ try {
432
+ const history = await this.getChatService().fetchAllMessages(this.activeSessionId);
433
+ if (epoch !== this.sessionEpoch)
434
+ return;
435
+ // Keep messages added while the history was loading (e.g. an optimistic
436
+ // user message) by appending any that aren't part of the fetched history.
437
+ const known = new Set(history.map(m => `${m.created_at}|${m.role}|${m.content}`));
438
+ const pending = this.messages.filter(m => !known.has(`${m.created_at}|${m.role}|${m.content}`));
439
+ this.messages = [...history, ...pending];
440
+ this.scrollToBottom(true);
441
+ }
442
+ catch (error) {
443
+ if (epoch !== this.sessionEpoch)
444
+ return;
445
+ console.warn('Failed to load chat history:', error);
446
+ }
447
+ this.startMessagePolling();
448
+ }
415
449
  async uploadFiles() {
416
- if (this.selectedFiles.length === 0 || !this.sessionId || !this.allowAttachments) {
450
+ if (this.selectedFiles.length === 0 || !this.activeSessionId || !this.allowAttachments) {
417
451
  return [];
418
452
  }
419
453
  this.isUploadingFiles = true;
420
454
  try {
421
455
  const uploadResult = await this.attachmentManager.uploadPendingFiles(this.selectedFiles, {
422
456
  apiBaseUrl: this.apiBaseUrl || 'https://www.openchatstudio.com',
423
- sessionId: this.sessionId,
457
+ sessionId: this.activeSessionId,
424
458
  participantId: this.getOrGenerateUserId(),
425
459
  participantName: this.userName,
426
460
  });
@@ -436,14 +470,14 @@ export class OcsChat {
436
470
  return;
437
471
  const epoch = this.sessionEpoch;
438
472
  // Start session if we don't have one yet
439
- if (!this.sessionId) {
473
+ if (!this.activeSessionId) {
440
474
  // Prevent concurrent session initialization
441
475
  if (this.isLoading) {
442
476
  return;
443
477
  }
444
478
  await this.startSession();
445
479
  // Check if session started successfully
446
- if (!this.sessionId) {
480
+ if (!this.activeSessionId) {
447
481
  return; // startSession already handled the error
448
482
  }
449
483
  }
@@ -504,7 +538,7 @@ export class OcsChat {
504
538
  if (this.versionNumber != null) {
505
539
  requestBody.version_number = this.versionNumber;
506
540
  }
507
- const data = await this.getChatService().sendMessage(this.sessionId, requestBody);
541
+ const data = await this.getChatService().sendMessage(this.activeSessionId, requestBody);
508
542
  if (epoch !== this.sessionEpoch)
509
543
  return;
510
544
  if (data.status === 'error') {
@@ -632,9 +666,15 @@ export class OcsChat {
632
666
  this.initializePosition();
633
667
  }
634
668
  // Resume polling for existing session (don't auto-start new sessions)
635
- if (this.sessionId) {
669
+ if (this.activeSessionId) {
636
670
  this.scrollToBottom(true);
637
- this.startMessagePolling();
671
+ if (this.isSessionBound() && this.messages.length === 0) {
672
+ // A bound widget that was hidden at load has not fetched its history yet.
673
+ void this.loadBoundSessionHistory();
674
+ }
675
+ else {
676
+ this.startMessagePolling();
677
+ }
638
678
  }
639
679
  }
640
680
  else {
@@ -642,7 +682,7 @@ export class OcsChat {
642
682
  }
643
683
  }
644
684
  startTaskPolling(taskId) {
645
- if (!this.sessionId)
685
+ if (!this.activeSessionId)
646
686
  return;
647
687
  this.currentPollTaskId = taskId;
648
688
  this.isTyping = true;
@@ -650,7 +690,7 @@ export class OcsChat {
650
690
  if (this.taskPollingHandle) {
651
691
  this.taskPollingHandle.cancel();
652
692
  }
653
- this.taskPollingHandle = this.getChatService().pollTask(this.sessionId, taskId, {
693
+ this.taskPollingHandle = this.getChatService().pollTask(this.activeSessionId, taskId, {
654
694
  onMessage: message => {
655
695
  this.messages = [...this.messages, message];
656
696
  this.saveSessionToStorage();
@@ -691,13 +731,13 @@ export class OcsChat {
691
731
  });
692
732
  }
693
733
  startMessagePolling() {
694
- if (!this.sessionId || this.currentPollTaskId || !this.visible) {
734
+ if (!this.activeSessionId || this.currentPollTaskId || !this.visible) {
695
735
  return;
696
736
  }
697
737
  if (this.messagePollingHandle) {
698
738
  return;
699
739
  }
700
- this.messagePollingHandle = this.getChatService().startMessagePolling(this.sessionId, {
740
+ this.messagePollingHandle = this.getChatService().startMessagePolling(this.activeSessionId, {
701
741
  getSince: () => { var _a; return (this.messages.length > 0 ? (_a = this.messages.at(-1)) === null || _a === void 0 ? void 0 : _a.created_at : undefined); },
702
742
  onMessages: messages => {
703
743
  if (messages.length === 0)
@@ -1050,13 +1090,13 @@ export class OcsChat {
1050
1090
  };
1051
1091
  }
1052
1092
  saveSessionToStorage() {
1053
- if (!this.persistentSession) {
1093
+ if (!this.persistentSession || this.isSessionBound()) {
1054
1094
  return;
1055
1095
  }
1056
1096
  const keys = this.getStorageKeys();
1057
1097
  try {
1058
- if (this.sessionId) {
1059
- localStorage.setItem(keys.sessionId, this.sessionId);
1098
+ if (this.activeSessionId) {
1099
+ localStorage.setItem(keys.sessionId, this.activeSessionId);
1060
1100
  localStorage.setItem(keys.lastActivity, new Date().toISOString());
1061
1101
  }
1062
1102
  localStorage.setItem(keys.messages, JSON.stringify(this.messages));
@@ -1173,6 +1213,9 @@ export class OcsChat {
1173
1213
  isKioskMode() {
1174
1214
  return this.mode === 'kiosk';
1175
1215
  }
1216
+ isSessionBound() {
1217
+ return !!this.sessionId;
1218
+ }
1176
1219
  isLocalStorageAvailable() {
1177
1220
  try {
1178
1221
  localStorage.setItem(OcsChat.LOCALSTORAGE_TEST_KEY, 'test');
@@ -1200,7 +1243,9 @@ export class OcsChat {
1200
1243
  async clearSession() {
1201
1244
  this.sessionEpoch += 1;
1202
1245
  this.clearSessionStorage();
1203
- this.sessionId = undefined;
1246
+ // A session provided by the host page (session-id prop) cannot be cleared;
1247
+ // stay bound to it. Unbound widgets start a new session on the next message.
1248
+ this.activeSessionId = this.sessionId;
1204
1249
  this.messages = [];
1205
1250
  this.isTyping = false;
1206
1251
  this.currentPollTaskId = '';
@@ -1208,6 +1253,11 @@ export class OcsChat {
1208
1253
  this.selectedFiles = [];
1209
1254
  }
1210
1255
  this.cleanup();
1256
+ if (this.isSessionBound()) {
1257
+ // The host-owned session cannot be cleared: reload its history and
1258
+ // resume polling so the widget doesn't end up in a dead state.
1259
+ void this.loadBoundSessionHistory();
1260
+ }
1211
1261
  }
1212
1262
  toggleFullscreen() {
1213
1263
  this.isFullscreen = !this.isFullscreen;
@@ -1216,10 +1266,10 @@ export class OcsChat {
1216
1266
  }
1217
1267
  render() {
1218
1268
  // Only show error state for critical errors that prevent the widget from functioning
1219
- if (this.error && !this.sessionId) {
1269
+ if (this.error && !this.activeSessionId) {
1220
1270
  return (h(Host, null, h("p", { class: "error-message" }, this.error)));
1221
1271
  }
1222
- return (h(Host, null, this.renderButton(), this.visible && (h("div", { ref: el => (this.chatWindowRef = el), id: "ocs-chat-window", class: this.getPositionClasses(), style: this.getPositionStyles() }, !this.isKioskMode() && (h("div", { class: `chat-header ${this.isDragging ? 'chat-header-dragging' : 'chat-header-draggable'}`, onMouseDown: this.handleMouseDown, onTouchStart: this.handleTouchStart }, h("div", { class: "drag-indicator" }, h("div", { class: "drag-dots header-button" }, h(GripDotsVerticalIcon, null))), h("div", { class: "header-text" }, this.translationManager.get('branding.headerText', this.headerText)), h("div", { class: "header-buttons" }, this.messages.length > 0 && (h("button", { class: "header-button", onClick: () => this.showConfirmationDialog(), title: this.translationManager.get('window.newChat'), "aria-label": this.translationManager.get('window.newChat') }, h(PlusWithCircleIcon, null))), this.allowFullScreen && (h("button", { class: "header-button fullscreen-button", onClick: () => this.toggleFullscreen(), title: this.isFullscreen ? this.translationManager.get('window.exitFullscreen') : this.translationManager.get('window.fullscreen'), "aria-label": this.isFullscreen ? this.translationManager.get('window.exitFullscreen') : this.translationManager.get('window.fullscreen') }, this.isFullscreen ? h(ArrowsPointingInIcon, null) : h(ArrowsPointingOutIcon, null))), h("button", { class: "header-button", onClick: () => (this.visible = false), "aria-label": this.translationManager.get('window.close') }, h(XMarkIcon, null))))), !this.isKioskMode() && this.showNewChatConfirmation && (h("div", { class: "confirmation-overlay" }, h("div", { class: "confirmation-dialog" }, h("div", { class: "confirmation-content" }, h("h3", { class: "confirmation-title" }, this.translationManager.get('modal.newChatTitle')), h("p", { class: "confirmation-message" }, this.translationManager.get('modal.newChatBody', this.newChatConfirmationMessage)), h("div", { class: "confirmation-buttons" }, h("button", { class: "confirmation-button confirmation-button-cancel", onClick: () => this.hideConfirmationDialog() }, this.translationManager.get('modal.cancel')), h("button", { class: "confirmation-button confirmation-button-confirm", onClick: () => this.confirmNewChat() }, this.translationManager.get('modal.confirm'))))))), h("div", { class: "chat-content" }, this.isLoading && !this.sessionId && (h("div", { class: "loading-container" }, h("div", { class: "loading-spinner" }), h("span", { class: "loading-text" }, this.translationManager.get('status.starting')))), h("div", { ref: el => (this.messageListRef = el), class: "messages-container" }, this.messages.length === 0 && this.getWelcomeMessages().length > 0 && (h("div", { class: "welcome-messages" }, this.getWelcomeMessages().map((message, index) => (h("div", { key: `welcome-${index}`, class: "message-row message-row-assistant" }, h("div", { class: "message-bubble message-bubble-assistant" }, h("div", { class: "chat-markdown", innerHTML: renderMarkdownComplete(message) }))))))), this.messages.map((message, index) => (h("div", { key: index, class: `message-row ${message.role === 'user' ? 'message-row-user' : 'message-row-assistant'}` }, h("div", { class: `message-bubble ${message.role === 'user' ? 'message-bubble-user' : message.role === 'assistant' ? 'message-bubble-assistant' : 'message-bubble-system'}` }, h("div", { class: "chat-markdown", innerHTML: renderMarkdownComplete(message.content) }), message.attachments && message.attachments.length > 0 && (h("div", { class: "message-attachments" }, message.attachments.map((attachment, attachmentIndex) => (h("div", { key: attachmentIndex, class: "flex items-center gap-[0.5em]" }, h("span", { class: "message-attachment-icon" }, h(PaperClipIcon, null)), h("span", { class: "message-attachment-name" }, attachment.name)))))), h("div", { class: "message-timestamp" }, this.formatTime(message.created_at)))))), this.isTyping && (h("div", null, h("div", { class: "typing-indicator" }, h("div", { class: "typing-progress" })), h("div", { class: "typing-text" }, h("span", null, this.typingProgressMessage || this.translationManager.get('status.typing', this.typingIndicatorText)), h("span", { class: "typing-dots loading" }))))), this.messages.length === 0 && this.getStarterQuestions().length > 0 && (h("div", { class: "starter-questions" }, this.getStarterQuestions().map((question, index) => (h("div", { key: `starter-${index}`, class: "starter-question-row" }, h("button", { class: "starter-question", onClick: () => this.handleStarterQuestionClick(question) }, question)))))), this.allowAttachments && this.selectedFiles.length > 0 && (h("div", { class: "selected-files-container" }, h("div", { class: "space-y-[0.25em]" }, this.selectedFiles.map((selectedFile, index) => (h("div", { key: index, class: "selected-file-item" }, h("div", { class: "flex items-center gap-[0.5em]" }, h("span", { class: "selected-file-icon" }, h(PaperClipIcon, null)), h("span", null, selectedFile.file.name), h("span", { class: "selected-file-size" }, "(", this.formatFileSize(selectedFile.file.size), ")"), selectedFile.error && h("span", { class: "selected-file-error" }, selectedFile.error), selectedFile.uploaded && (h("span", { class: "selected-file-success-icon" }, h(CheckDocumentIcon, null)))), h("button", { onClick: () => this.removeSelectedFile(index), class: "selected-file-remove-button", "aria-label": this.translationManager.get('attach.remove') }, h(XIcon, null)))))))), h("div", { class: "input-area" }, h("div", { class: "input-container" }, h("textarea", { ref: el => (this.textareaRef = el), class: "message-textarea", rows: 1, placeholder: this.translationManager.get('composer.placeholder'), value: this.messageInput, onInput: e => this.handleInputChange(e), onKeyPress: e => this.handleKeyPress(e), disabled: this.isTyping || this.isUploadingFiles || this.isLoading }), this.allowAttachments && (h("input", { ref: el => {
1272
+ return (h(Host, null, this.renderButton(), this.visible && (h("div", { ref: el => (this.chatWindowRef = el), id: "ocs-chat-window", class: this.getPositionClasses(), style: this.getPositionStyles() }, !this.isKioskMode() && (h("div", { class: `chat-header ${this.isDragging ? 'chat-header-dragging' : 'chat-header-draggable'}`, onMouseDown: this.handleMouseDown, onTouchStart: this.handleTouchStart }, h("div", { class: "drag-indicator" }, h("div", { class: "drag-dots header-button" }, h(GripDotsVerticalIcon, null))), h("div", { class: "header-text" }, this.translationManager.get('branding.headerText', this.headerText)), h("div", { class: "header-buttons" }, this.messages.length > 0 && !this.isSessionBound() && (h("button", { class: "header-button", onClick: () => this.showConfirmationDialog(), title: this.translationManager.get('window.newChat'), "aria-label": this.translationManager.get('window.newChat') }, h(PlusWithCircleIcon, null))), this.allowFullScreen && (h("button", { class: "header-button fullscreen-button", onClick: () => this.toggleFullscreen(), title: this.isFullscreen ? this.translationManager.get('window.exitFullscreen') : this.translationManager.get('window.fullscreen'), "aria-label": this.isFullscreen ? this.translationManager.get('window.exitFullscreen') : this.translationManager.get('window.fullscreen') }, this.isFullscreen ? h(ArrowsPointingInIcon, null) : h(ArrowsPointingOutIcon, null))), h("button", { class: "header-button", onClick: () => (this.visible = false), "aria-label": this.translationManager.get('window.close') }, h(XMarkIcon, null))))), !this.isKioskMode() && this.showNewChatConfirmation && (h("div", { class: "confirmation-overlay" }, h("div", { class: "confirmation-dialog" }, h("div", { class: "confirmation-content" }, h("h3", { class: "confirmation-title" }, this.translationManager.get('modal.newChatTitle')), h("p", { class: "confirmation-message" }, this.translationManager.get('modal.newChatBody', this.newChatConfirmationMessage)), h("div", { class: "confirmation-buttons" }, h("button", { class: "confirmation-button confirmation-button-cancel", onClick: () => this.hideConfirmationDialog() }, this.translationManager.get('modal.cancel')), h("button", { class: "confirmation-button confirmation-button-confirm", onClick: () => this.confirmNewChat() }, this.translationManager.get('modal.confirm'))))))), h("div", { class: "chat-content" }, this.isLoading && !this.activeSessionId && (h("div", { class: "loading-container" }, h("div", { class: "loading-spinner" }), h("span", { class: "loading-text" }, this.translationManager.get('status.starting')))), h("div", { ref: el => (this.messageListRef = el), class: "messages-container" }, this.messages.length === 0 && this.getWelcomeMessages().length > 0 && (h("div", { class: "welcome-messages" }, this.getWelcomeMessages().map((message, index) => (h("div", { key: `welcome-${index}`, class: "message-row message-row-assistant" }, h("div", { class: "message-bubble message-bubble-assistant" }, h("div", { class: "chat-markdown", innerHTML: renderMarkdownComplete(message) }))))))), this.messages.map((message, index) => (h("div", { key: index, class: `message-row ${message.role === 'user' ? 'message-row-user' : 'message-row-assistant'}` }, h("div", { class: `message-bubble ${message.role === 'user' ? 'message-bubble-user' : message.role === 'assistant' ? 'message-bubble-assistant' : 'message-bubble-system'}` }, h("div", { class: "chat-markdown", innerHTML: renderMarkdownComplete(message.content) }), message.attachments && message.attachments.length > 0 && (h("div", { class: "message-attachments" }, message.attachments.map((attachment, attachmentIndex) => (h("div", { key: attachmentIndex, class: "flex items-center gap-[0.5em]" }, h("span", { class: "message-attachment-icon" }, h(PaperClipIcon, null)), h("span", { class: "message-attachment-name" }, attachment.name)))))), h("div", { class: "message-timestamp" }, this.formatTime(message.created_at)))))), this.isTyping && (h("div", null, h("div", { class: "typing-indicator" }, h("div", { class: "typing-progress" })), h("div", { class: "typing-text" }, h("span", null, this.typingProgressMessage || this.translationManager.get('status.typing', this.typingIndicatorText)), h("span", { class: "typing-dots loading" }))))), this.messages.length === 0 && this.getStarterQuestions().length > 0 && (h("div", { class: "starter-questions" }, this.getStarterQuestions().map((question, index) => (h("div", { key: `starter-${index}`, class: "starter-question-row" }, h("button", { class: "starter-question", onClick: () => this.handleStarterQuestionClick(question) }, question)))))), this.allowAttachments && this.selectedFiles.length > 0 && (h("div", { class: "selected-files-container" }, h("div", { class: "space-y-[0.25em]" }, this.selectedFiles.map((selectedFile, index) => (h("div", { key: index, class: "selected-file-item" }, h("div", { class: "flex items-center gap-[0.5em]" }, h("span", { class: "selected-file-icon" }, h(PaperClipIcon, null)), h("span", null, selectedFile.file.name), h("span", { class: "selected-file-size" }, "(", this.formatFileSize(selectedFile.file.size), ")"), selectedFile.error && h("span", { class: "selected-file-error" }, selectedFile.error), selectedFile.uploaded && (h("span", { class: "selected-file-success-icon" }, h(CheckDocumentIcon, null)))), h("button", { onClick: () => this.removeSelectedFile(index), class: "selected-file-remove-button", "aria-label": this.translationManager.get('attach.remove') }, h(XIcon, null)))))))), h("div", { class: "input-area" }, h("div", { class: "input-container" }, h("textarea", { ref: el => (this.textareaRef = el), class: "message-textarea", rows: 1, placeholder: this.translationManager.get('composer.placeholder'), value: this.messageInput, onInput: e => this.handleInputChange(e), onKeyPress: e => this.handleKeyPress(e), disabled: this.isTyping || this.isUploadingFiles || this.isLoading }), this.allowAttachments && (h("input", { ref: el => {
1223
1273
  // Unclear why but after removing all attachments this is being set to `null`.
1224
1274
  if (el) {
1225
1275
  this.fileInputRef = el;
@@ -1563,7 +1613,7 @@ export class OcsChat {
1563
1613
  "optional": false,
1564
1614
  "docs": {
1565
1615
  "tags": [],
1566
- "text": "Whether to persist session data to local storage to allow resuming previous conversations after page reload."
1616
+ "text": "Whether to persist session data to local storage to allow resuming previous conversations after page reload.\nIgnored when `sessionId` is provided."
1567
1617
  },
1568
1618
  "getter": false,
1569
1619
  "setter": false,
@@ -1731,6 +1781,25 @@ export class OcsChat {
1731
1781
  "getter": false,
1732
1782
  "setter": false,
1733
1783
  "reflect": false
1784
+ },
1785
+ "sessionId": {
1786
+ "type": "string",
1787
+ "attribute": "session-id",
1788
+ "mutable": false,
1789
+ "complexType": {
1790
+ "original": "string",
1791
+ "resolved": "string",
1792
+ "references": {}
1793
+ },
1794
+ "required": false,
1795
+ "optional": true,
1796
+ "docs": {
1797
+ "tags": [],
1798
+ "text": "The ID of an existing chat session to connect to. When provided, the widget\nis bound to that session: local session persistence is disabled and the\nmessage history is loaded from the server. Intended for host pages that\ncreate the session server-side (e.g. the OCS web chat page)."
1799
+ },
1800
+ "getter": false,
1801
+ "setter": false,
1802
+ "reflect": false
1734
1803
  }
1735
1804
  };
1736
1805
  }
@@ -1738,7 +1807,7 @@ export class OcsChat {
1738
1807
  return {
1739
1808
  "error": {},
1740
1809
  "messages": {},
1741
- "sessionId": {},
1810
+ "activeSessionId": {},
1742
1811
  "isLoading": {},
1743
1812
  "isTyping": {},
1744
1813
  "typingProgressMessage": {},