@microsoft/omnichannel-chat-widget 1.8.4-main.cbab5fc → 1.8.4-main.cc63f01

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 (143) hide show
  1. package/README.md +13 -3
  2. package/lib/cjs/common/Constants.js +5 -0
  3. package/lib/cjs/common/facades/FacadeChatSDK.js +235 -9
  4. package/lib/cjs/common/telemetry/TelemetryConstants.js +14 -0
  5. package/lib/cjs/common/telemetry/TelemetryManager.js +6 -1
  6. package/lib/cjs/common/telemetry/loggers/appInsightsLogger.js +7 -7
  7. package/lib/cjs/common/telemetry/sanitizeSasInPayload.js +82 -0
  8. package/lib/cjs/common/utils/xssUtils.js +23 -51
  9. package/lib/cjs/common/utils.js +106 -17
  10. package/lib/cjs/components/citationpanestateful/CitationPaneStateful.js +8 -1
  11. package/lib/cjs/components/confirmationpanestateful/ConfirmationPaneStateful.js +12 -1
  12. package/lib/cjs/components/emailtranscriptpanestateful/EmailTranscriptPaneStateful.js +36 -13
  13. package/lib/cjs/components/errorboundary/ErrorBoundary.js +2 -1
  14. package/lib/cjs/components/livechatwidget/LiveChatWidget.js +9 -1
  15. package/lib/cjs/components/livechatwidget/common/ActivitySubscriber/BotAuthActivitySubscriber.js +23 -6
  16. package/lib/cjs/components/livechatwidget/common/ChatWidgetEvents.js +1 -0
  17. package/lib/cjs/components/livechatwidget/common/PersistentConversationHandler.js +9 -0
  18. package/lib/cjs/components/livechatwidget/common/authHelper.js +44 -4
  19. package/lib/cjs/components/livechatwidget/common/createAdapter.js +3 -2
  20. package/lib/cjs/components/livechatwidget/common/createMarkdown.js +98 -5
  21. package/lib/cjs/components/livechatwidget/common/endChat.js +6 -0
  22. package/lib/cjs/components/livechatwidget/common/initWebChatComposer.js +186 -1
  23. package/lib/cjs/components/livechatwidget/common/liveChatConfigUtils.js +36 -4
  24. package/lib/cjs/components/livechatwidget/common/startChat.js +31 -14
  25. package/lib/cjs/components/livechatwidget/livechatwidgetstateful/LiveChatWidgetStateful.js +124 -5
  26. package/lib/cjs/components/postchatloadingpanestateful/PostChatLoadingPaneStateful.js +15 -3
  27. package/lib/cjs/components/postchatsurveypanestateful/PostChatSurveyPaneStateful.js +7 -4
  28. package/lib/cjs/components/prechatsurveypanestateful/PreChatSurveyPaneStateful.js +68 -2
  29. package/lib/cjs/components/prechatsurveypanestateful/common/defaultStyles/defaultGeneralPreChatSurveyPaneStyleProps.js +2 -1
  30. package/lib/cjs/components/proactivechatpanestateful/ProactiveChatPaneStateful.js +0 -1
  31. package/lib/cjs/components/webchatcontainerstateful/WebChatContainerStateful.js +157 -34
  32. package/lib/cjs/components/webchatcontainerstateful/common/DesignerChatAdapter.js +10 -0
  33. package/lib/cjs/components/webchatcontainerstateful/common/activityConverters/convertPersistentChatHistoryMessageToActivity.js +117 -16
  34. package/lib/cjs/components/webchatcontainerstateful/common/defaultProps/defaultMiddlewareLocalizedTexts.js +3 -0
  35. package/lib/cjs/components/webchatcontainerstateful/common/defaultProps/defaultWebChatContainerStatefulProps.js +2 -1
  36. package/lib/cjs/components/webchatcontainerstateful/common/defaultStyles/defaultAdaptiveCardStyles.js +5 -1
  37. package/lib/cjs/components/webchatcontainerstateful/common/defaultStyles/defaultWebChatStyles.js +2 -2
  38. package/lib/cjs/components/webchatcontainerstateful/common/utils/chatAdapterUtils.js +3 -1
  39. package/lib/cjs/components/webchatcontainerstateful/common/utils/citationA11y.js +195 -0
  40. package/lib/cjs/components/webchatcontainerstateful/webchatcontroller/WebChatEventSubscribers.js +13 -2
  41. package/lib/cjs/components/webchatcontainerstateful/webchatcontroller/middlewares/renderingmiddlewares/activities/LazyLoadActivity.js +160 -167
  42. package/lib/cjs/components/webchatcontainerstateful/webchatcontroller/middlewares/renderingmiddlewares/activityMiddleware.js +27 -8
  43. package/lib/cjs/components/webchatcontainerstateful/webchatcontroller/middlewares/renderingmiddlewares/attachmentMiddleware.js +2 -1
  44. package/lib/cjs/components/webchatcontainerstateful/webchatcontroller/middlewares/renderingmiddlewares/attachments/AdaptiveCardAccessibilityWrapper.js +203 -0
  45. package/lib/cjs/components/webchatcontainerstateful/webchatcontroller/middlewares/renderingmiddlewares/defaultStyles/defaultAvatarTextStyles.js +1 -1
  46. package/lib/cjs/components/webchatcontainerstateful/webchatcontroller/middlewares/renderingmiddlewares/defaultStyles/defaultSystemMessageStyles.js +8 -3
  47. package/lib/cjs/components/webchatcontainerstateful/webchatcontroller/middlewares/renderingmiddlewares/defaultStyles/defaultTimestampRetryStyles.js +8 -1
  48. package/lib/cjs/components/webchatcontainerstateful/webchatcontroller/middlewares/renderingmiddlewares/timestamps/NotDeliveredTimestamp.js +5 -13
  49. package/lib/cjs/components/webchatcontainerstateful/webchatcontroller/middlewares/storemiddlewares/attachmentSentAnnouncementMiddleware.js +81 -0
  50. package/lib/cjs/components/webchatcontainerstateful/webchatcontroller/middlewares/storemiddlewares/attachmentUploadValidatorMiddleware.js +29 -1
  51. package/lib/cjs/components/webchatcontainerstateful/webchatcontroller/middlewares/storemiddlewares/localizedStringsBotInitialsMiddleware.js +52 -8
  52. package/lib/cjs/components/webchatcontainerstateful/webchatcontroller/notification/NotificationHandler.js +55 -1
  53. package/lib/cjs/contexts/common/LiveChatWidgetActionType.js +1 -0
  54. package/lib/cjs/contexts/common/LiveChatWidgetContextInitialState.js +17 -1
  55. package/lib/cjs/contexts/createReducer.js +15 -0
  56. package/lib/cjs/controller/componentController.js +13 -1
  57. package/lib/cjs/plugins/newMessageEventHandler.js +20 -3
  58. package/lib/esm/common/Constants.js +5 -0
  59. package/lib/esm/common/facades/FacadeChatSDK.js +236 -10
  60. package/lib/esm/common/telemetry/TelemetryConstants.js +14 -0
  61. package/lib/esm/common/telemetry/TelemetryManager.js +6 -1
  62. package/lib/esm/common/telemetry/loggers/appInsightsLogger.js +7 -7
  63. package/lib/esm/common/telemetry/sanitizeSasInPayload.js +75 -0
  64. package/lib/esm/common/utils/xssUtils.js +23 -51
  65. package/lib/esm/common/utils.js +99 -14
  66. package/lib/esm/components/citationpanestateful/CitationPaneStateful.js +8 -1
  67. package/lib/esm/components/confirmationpanestateful/ConfirmationPaneStateful.js +12 -1
  68. package/lib/esm/components/emailtranscriptpanestateful/EmailTranscriptPaneStateful.js +37 -14
  69. package/lib/esm/components/errorboundary/ErrorBoundary.js +4 -2
  70. package/lib/esm/components/livechatwidget/LiveChatWidget.js +9 -1
  71. package/lib/esm/components/livechatwidget/common/ActivitySubscriber/BotAuthActivitySubscriber.js +23 -6
  72. package/lib/esm/components/livechatwidget/common/ChatWidgetEvents.js +1 -0
  73. package/lib/esm/components/livechatwidget/common/PersistentConversationHandler.js +9 -0
  74. package/lib/esm/components/livechatwidget/common/authHelper.js +44 -4
  75. package/lib/esm/components/livechatwidget/common/createAdapter.js +3 -2
  76. package/lib/esm/components/livechatwidget/common/createMarkdown.js +98 -5
  77. package/lib/esm/components/livechatwidget/common/endChat.js +6 -0
  78. package/lib/esm/components/livechatwidget/common/initWebChatComposer.js +186 -1
  79. package/lib/esm/components/livechatwidget/common/liveChatConfigUtils.js +33 -2
  80. package/lib/esm/components/livechatwidget/common/startChat.js +31 -14
  81. package/lib/esm/components/livechatwidget/livechatwidgetstateful/LiveChatWidgetStateful.js +125 -6
  82. package/lib/esm/components/postchatloadingpanestateful/PostChatLoadingPaneStateful.js +16 -4
  83. package/lib/esm/components/postchatsurveypanestateful/PostChatSurveyPaneStateful.js +7 -4
  84. package/lib/esm/components/prechatsurveypanestateful/PreChatSurveyPaneStateful.js +69 -3
  85. package/lib/esm/components/prechatsurveypanestateful/common/defaultStyles/defaultGeneralPreChatSurveyPaneStyleProps.js +2 -1
  86. package/lib/esm/components/proactivechatpanestateful/ProactiveChatPaneStateful.js +1 -2
  87. package/lib/esm/components/webchatcontainerstateful/WebChatContainerStateful.js +158 -35
  88. package/lib/esm/components/webchatcontainerstateful/common/DesignerChatAdapter.js +10 -0
  89. package/lib/esm/components/webchatcontainerstateful/common/activityConverters/convertPersistentChatHistoryMessageToActivity.js +117 -16
  90. package/lib/esm/components/webchatcontainerstateful/common/defaultProps/defaultMiddlewareLocalizedTexts.js +3 -0
  91. package/lib/esm/components/webchatcontainerstateful/common/defaultProps/defaultWebChatContainerStatefulProps.js +2 -1
  92. package/lib/esm/components/webchatcontainerstateful/common/defaultStyles/defaultAdaptiveCardStyles.js +5 -1
  93. package/lib/esm/components/webchatcontainerstateful/common/defaultStyles/defaultWebChatStyles.js +2 -2
  94. package/lib/esm/components/webchatcontainerstateful/common/utils/chatAdapterUtils.js +3 -1
  95. package/lib/esm/components/webchatcontainerstateful/common/utils/citationA11y.js +188 -0
  96. package/lib/esm/components/webchatcontainerstateful/webchatcontroller/WebChatEventSubscribers.js +13 -2
  97. package/lib/esm/components/webchatcontainerstateful/webchatcontroller/middlewares/renderingmiddlewares/activities/LazyLoadActivity.js +160 -171
  98. package/lib/esm/components/webchatcontainerstateful/webchatcontroller/middlewares/renderingmiddlewares/activityMiddleware.js +24 -6
  99. package/lib/esm/components/webchatcontainerstateful/webchatcontroller/middlewares/renderingmiddlewares/attachmentMiddleware.js +2 -1
  100. package/lib/esm/components/webchatcontainerstateful/webchatcontroller/middlewares/renderingmiddlewares/attachments/AdaptiveCardAccessibilityWrapper.js +195 -0
  101. package/lib/esm/components/webchatcontainerstateful/webchatcontroller/middlewares/renderingmiddlewares/defaultStyles/defaultAvatarTextStyles.js +1 -1
  102. package/lib/esm/components/webchatcontainerstateful/webchatcontroller/middlewares/renderingmiddlewares/defaultStyles/defaultSystemMessageStyles.js +8 -3
  103. package/lib/esm/components/webchatcontainerstateful/webchatcontroller/middlewares/renderingmiddlewares/defaultStyles/defaultTimestampRetryStyles.js +8 -1
  104. package/lib/esm/components/webchatcontainerstateful/webchatcontroller/middlewares/renderingmiddlewares/timestamps/NotDeliveredTimestamp.js +5 -13
  105. package/lib/esm/components/webchatcontainerstateful/webchatcontroller/middlewares/storemiddlewares/attachmentSentAnnouncementMiddleware.js +74 -0
  106. package/lib/esm/components/webchatcontainerstateful/webchatcontroller/middlewares/storemiddlewares/attachmentUploadValidatorMiddleware.js +29 -1
  107. package/lib/esm/components/webchatcontainerstateful/webchatcontroller/middlewares/storemiddlewares/channelDataMiddleware.js +1 -0
  108. package/lib/esm/components/webchatcontainerstateful/webchatcontroller/middlewares/storemiddlewares/localizedStringsBotInitialsMiddleware.js +52 -8
  109. package/lib/esm/components/webchatcontainerstateful/webchatcontroller/notification/NotificationHandler.js +55 -1
  110. package/lib/esm/contexts/common/LiveChatWidgetActionType.js +1 -0
  111. package/lib/esm/contexts/common/LiveChatWidgetContextInitialState.js +17 -1
  112. package/lib/esm/contexts/createReducer.js +15 -0
  113. package/lib/esm/controller/componentController.js +13 -1
  114. package/lib/esm/plugins/newMessageEventHandler.js +20 -3
  115. package/lib/types/common/Constants.d.ts +4 -0
  116. package/lib/types/common/facades/FacadeChatSDK.d.ts +29 -0
  117. package/lib/types/common/facades/types/IFacadeChatSDKInput.d.ts +3 -1
  118. package/lib/types/common/telemetry/TelemetryConstants.d.ts +14 -2
  119. package/lib/types/common/telemetry/sanitizeSasInPayload.d.ts +24 -0
  120. package/lib/types/common/utils/xssUtils.d.ts +5 -21
  121. package/lib/types/common/utils.d.ts +12 -2
  122. package/lib/types/components/errorboundary/ErrorBoundary.d.ts +1 -1
  123. package/lib/types/components/livechatwidget/common/ActivitySubscriber/BotAuthActivitySubscriber.d.ts +1 -0
  124. package/lib/types/components/livechatwidget/common/ChatWidgetEvents.d.ts +2 -1
  125. package/lib/types/components/livechatwidget/common/authHelper.d.ts +9 -2
  126. package/lib/types/components/livechatwidget/common/liveChatConfigUtils.d.ts +11 -0
  127. package/lib/types/components/livechatwidget/interfaces/IBotAuthActivitySubscriberOptionalParams.d.ts +1 -0
  128. package/lib/types/components/webchatcontainerstateful/common/utils/chatAdapterUtils.d.ts +1 -1
  129. package/lib/types/components/webchatcontainerstateful/common/utils/citationA11y.d.ts +1 -0
  130. package/lib/types/components/webchatcontainerstateful/interfaces/IAdaptiveCardStyles.d.ts +3 -0
  131. package/lib/types/components/webchatcontainerstateful/interfaces/IBotAuthConfig.d.ts +7 -0
  132. package/lib/types/components/webchatcontainerstateful/interfaces/IExtendedChatConffig.d.ts +1 -1
  133. package/lib/types/components/webchatcontainerstateful/interfaces/IWebChatContainerStatefulProps.d.ts +7 -0
  134. package/lib/types/components/webchatcontainerstateful/webchatcontroller/middlewares/renderingmiddlewares/activities/LazyLoadActivity.d.ts +14 -38
  135. package/lib/types/components/webchatcontainerstateful/webchatcontroller/middlewares/renderingmiddlewares/activityMiddleware.d.ts +2 -0
  136. package/lib/types/components/webchatcontainerstateful/webchatcontroller/middlewares/renderingmiddlewares/attachments/AdaptiveCardAccessibilityWrapper.d.ts +18 -0
  137. package/lib/types/components/webchatcontainerstateful/webchatcontroller/middlewares/renderingmiddlewares/defaultStyles/defaultSystemMessageStyles.d.ts +3 -0
  138. package/lib/types/components/webchatcontainerstateful/webchatcontroller/middlewares/storemiddlewares/attachmentSentAnnouncementMiddleware.d.ts +12 -0
  139. package/lib/types/components/webchatcontainerstateful/webchatcontroller/notification/NotificationHandler.d.ts +7 -0
  140. package/lib/types/contexts/common/ILiveChatWidgetContext.d.ts +1 -0
  141. package/lib/types/contexts/common/ILiveChatWidgetLocalizedTexts.d.ts +17 -0
  142. package/lib/types/contexts/common/LiveChatWidgetActionType.d.ts +2 -1
  143. package/package.json +37 -9
@@ -7,70 +7,42 @@ exports.detectAndCleanXSS = void 0;
7
7
  var _dompurify = _interopRequireDefault(require("dompurify"));
8
8
  function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; }
9
9
  /**
10
- * Detects potential Cross-Site Scripting (XSS) attacks in text input and sanitizes the content.
10
+ * Sanitizes text input and detects XSS attack patterns.
11
11
  *
12
- * This function performs comprehensive XSS detection using pattern matching for common attack vectors
13
- * and then sanitizes the input using DOMPurify with strict configuration. It's designed to protect
14
- * against various XSS techniques including script injection, event handler injection, style-based
15
- * attacks, and encoded payloads.
12
+ * Sanitizes first with DOMPurify, then checks for malicious patterns in both
13
+ * the original and sanitized text to catch mutation XSS attacks.
16
14
  *
17
- * Security patterns detected:
18
- * - JavaScript protocol URLs (javascript:)
19
- * - HTML event handlers (onmouseover, onclick, etc.)
20
- * - Script tags (<script>)
21
- * - CSS expression() functions
22
- * - CSS url() functions
23
- * - Position-based CSS attacks (position: fixed/absolute)
24
- * - VBScript protocol URLs
25
- * - Data URLs with HTML content
26
- * - Fragment identifiers with escaped quotes
27
- * - HTML entity-encoded angle brackets
28
- *
29
- * @param text - The input text to be analyzed and sanitized
30
- * @returns An object containing:
31
- * - cleanText: The sanitized version of the input text with all HTML tags and attributes removed
32
- * - isXSSDetected: Boolean flag indicating whether potential XSS patterns were found in the original text
15
+ * @param text - Input text to sanitize
16
+ * @returns Object with cleanText (sanitized) and isXSSDetected flag
33
17
  */
34
18
  const detectAndCleanXSS = text => {
35
- // Comprehensive array of regular expressions to detect common XSS attack patterns
36
- const xssPatterns = [/javascript\s*:/gi,
37
- // JavaScript protocol URLs (with optional spaces)
38
- /vbscript\s*:/gi,
39
- // VBScript protocol URLs (with optional spaces)
40
- /on\w+\s*=/gi,
41
- // HTML event handlers (onmouseover, onclick, onload, etc.)
42
- /<\s*script/gi,
43
- // Script tag opening (with optional spaces)
44
- /expression\s*\(/gi,
45
- // CSS expression() function (IE-specific)
46
- /url\s*\(/gi,
47
- // CSS url() function
48
- /style\s*=.*position\s*:\s*fixed/gi,
49
- // CSS position fixed attacks
50
- /style\s*=.*position\s*:\s*absolute/gi,
51
- // CSS position absolute attacks
52
- /data\s*:\s*text\s*\/\s*html/gi,
53
- // Data URLs containing HTML
54
- /#.*\\"/gi,
55
- // Fragment identifiers with escaped quotes
56
- /&gt;.*&lt;/gi // HTML entity-encoded angle brackets indicating tag structure
57
- ];
58
-
59
- // Check if any XSS patterns are detected in the input text
60
- const isXSSDetected = xssPatterns.some(pattern => pattern.test(text));
61
-
62
- // Clean the text using DOMPurify with strict config
19
+ // Sanitize first to prevent mutation XSS (e.g., "s<iframe></iframe>tyle" "style")
63
20
  const cleanText = _dompurify.default.sanitize(text, {
64
21
  ALLOWED_TAGS: [],
65
- // No HTML tags allowed in title
66
22
  ALLOWED_ATTR: [],
67
23
  KEEP_CONTENT: true,
68
- // Keep text content
69
24
  ALLOW_DATA_ATTR: false,
70
25
  ALLOW_UNKNOWN_PROTOCOLS: false,
71
26
  SANITIZE_DOM: true,
72
27
  FORCE_BODY: false
73
28
  });
29
+ const contentChanged = text !== cleanText;
30
+
31
+ // Non-global regex patterns to avoid stateful .test() issues
32
+ const xssPatterns = [/javascript\s*:/i, /vbscript\s*:/i, /on\w+\s*=/i,
33
+ // Event handlers
34
+ /<\s*script/i, /<\s*iframe/i, /<\s*object/i, /<\s*embed/i, /<\s*svg/i, /expression\s*\(/i,
35
+ // IE CSS expressions
36
+ /style\s*=.*position\s*:\s*(fixed|absolute)/i, /data\s*:\s*text\s*\/\s*html/i, /#.*\\"/i, /&(lt|gt|#x3c|#60|#x3e|#62);/i,
37
+ // HTML entities
38
+ /&#x?[0-9a-f]+;.*</i, /\u003c.*\u003e/i,
39
+ // Unicode escapes
40
+ /src\s*=\s*["']?\s*javascript:/i, /href\s*=\s*["']?\s*javascript:/i];
41
+ const hasXSSPattern = xssPatterns.some(pattern => {
42
+ return pattern.test(text) || pattern.test(cleanText);
43
+ });
44
+ const hasHTMLStructure = /<[^>]+>/.test(text) && !/<[^>]+>/.test(cleanText);
45
+ const isXSSDetected = contentChanged || hasXSSPattern || hasHTMLStructure;
74
46
  return {
75
47
  cleanText,
76
48
  isXSSDetected
@@ -3,11 +3,13 @@
3
3
  Object.defineProperty(exports, "__esModule", {
4
4
  value: true
5
5
  });
6
- exports.getCustomEventValue = exports.getConversationDetailsCall = exports.getBroadcastChannelName = exports.formatTemplateString = exports.findParentFocusableElementsWithoutChildContainer = exports.findAllFocusableElement = exports.extractPreChatSurveyResponseValues = exports.escapeHtml = exports.debounceLeading = exports.createTimer = exports.createFileAndDownload = exports.checkContactIdError = exports.changeLanguageCodeFormatForWebChat = exports.addDelayInMs = void 0;
6
+ exports.getCustomEventValue = exports.getConversationDetailsCall = exports.getBroadcastChannelName = exports.formatTemplateString = exports.findParentFocusableElementsWithoutChildContainer = exports.findAllFocusableElement = exports.extractPreChatSurveyResponseValues = exports.escapeHtml = exports.debounceLeading = exports.createTimer = exports.createFileAndDownload = exports.checkContactIdError = exports.changeLanguageCodeFormatForWebChat = exports.announceMessageImmediately = exports.addDelayInMs = void 0;
7
7
  exports.getDeviceType = getDeviceType;
8
8
  exports.getWidgetEndChatEventName = exports.getWidgetCacheIdfromProps = exports.getWidgetCacheId = exports.getTimestampHourMinute = exports.getStateFromCache = exports.getLocaleDirection = exports.getIconText = exports.getDomain = void 0;
9
9
  exports.isEndConversationDueToOverflowActivity = isEndConversationDueToOverflowActivity;
10
- exports.setTabIndices = exports.setOcUserAgent = exports.setFocusOnSendBox = exports.setFocusOnElement = exports.preventFocusToMoveOutOfElement = exports.parseLowerCaseString = exports.parseAdaptiveCardPayload = exports.newGuid = exports.isValidCustomEvent = exports.isUndefinedOrEmpty = exports.isThisSessionPopout = exports.isNullOrUndefined = exports.isNullOrEmptyString = void 0;
10
+ exports.parseAdaptiveCardPayload = exports.newGuid = exports.isValidCustomEvent = exports.isUndefinedOrEmpty = exports.isThisSessionPopout = exports.isNullOrUndefined = exports.isNullOrEmptyString = void 0;
11
+ exports.parseBooleanFromConfig = parseBooleanFromConfig;
12
+ exports.setTabIndices = exports.setOcUserAgent = exports.setFocusOnSendBox = exports.setFocusOnElement = exports.setAriaHiddenForSiblings = exports.preventFocusToMoveOutOfElement = exports.parseLowerCaseString = void 0;
11
13
  var _Constants = require("./Constants");
12
14
  var _TelemetryConstants = require("./telemetry/TelemetryConstants");
13
15
  var _omnichannelChatComponents = require("@microsoft/omnichannel-chat-components");
@@ -83,28 +85,69 @@ exports.findAllFocusableElement = findAllFocusableElement;
83
85
  const preventFocusToMoveOutOfElement = elementId => {
84
86
  const container = document.getElementById(elementId);
85
87
  if (!container) {
86
- return;
88
+ return () => {/* no-op */};
87
89
  }
88
90
  const focusableElements = findAllFocusableElement(container);
89
91
  if (!focusableElements) {
90
- return;
92
+ return () => {/* no-op */};
91
93
  }
92
94
  const firstFocusableElement = focusableElements[0];
93
95
  const lastFocusableElement = focusableElements[focusableElements.length - 1];
94
- firstFocusableElement.onkeydown = e => {
95
- if (e.shiftKey && e.key === _KeyCodes.KeyCodes.TAB) {
96
- e.preventDefault();
97
- lastFocusableElement === null || lastFocusableElement === void 0 ? void 0 : lastFocusableElement.focus();
98
- }
99
- };
100
- lastFocusableElement.onkeydown = e => {
101
- if (!e.shiftKey && e.key === _KeyCodes.KeyCodes.TAB) {
102
- e.preventDefault();
103
- firstFocusableElement === null || firstFocusableElement === void 0 ? void 0 : firstFocusableElement.focus();
104
- }
105
- };
96
+ const cleanups = [];
97
+ if (firstFocusableElement === lastFocusableElement) {
98
+ const handler = e => {
99
+ if (e.key === _KeyCodes.KeyCodes.TAB && !e.shiftKey) {
100
+ e.preventDefault();
101
+ firstFocusableElement.focus();
102
+ } else if (e.key === _KeyCodes.KeyCodes.TAB && e.shiftKey) {
103
+ e.preventDefault();
104
+ firstFocusableElement.focus();
105
+ }
106
+ };
107
+ firstFocusableElement.addEventListener("keydown", handler);
108
+ cleanups.push(() => firstFocusableElement.removeEventListener("keydown", handler));
109
+ } else {
110
+ const firstHandler = e => {
111
+ if (e.shiftKey && e.key === _KeyCodes.KeyCodes.TAB) {
112
+ e.preventDefault();
113
+ lastFocusableElement === null || lastFocusableElement === void 0 ? void 0 : lastFocusableElement.focus();
114
+ }
115
+ };
116
+ firstFocusableElement.addEventListener("keydown", firstHandler);
117
+ cleanups.push(() => firstFocusableElement.removeEventListener("keydown", firstHandler));
118
+ const lastHandler = e => {
119
+ if (!e.shiftKey && e.key === _KeyCodes.KeyCodes.TAB) {
120
+ e.preventDefault();
121
+ firstFocusableElement === null || firstFocusableElement === void 0 ? void 0 : firstFocusableElement.focus();
122
+ }
123
+ };
124
+ lastFocusableElement.addEventListener("keydown", lastHandler);
125
+ cleanups.push(() => lastFocusableElement.removeEventListener("keydown", lastHandler));
126
+ }
127
+ return () => cleanups.forEach(fn => fn());
106
128
  };
107
129
  exports.preventFocusToMoveOutOfElement = preventFocusToMoveOutOfElement;
130
+ const setAriaHiddenForSiblings = (elementId, shouldHide, stateMap) => {
131
+ const element = document.getElementById(elementId);
132
+ if (!(element !== null && element !== void 0 && element.parentElement)) return;
133
+ Array.from(element.parentElement.children).forEach(sibling => {
134
+ if (sibling !== element) {
135
+ if (shouldHide) {
136
+ stateMap.set(sibling, sibling.getAttribute("aria-hidden"));
137
+ sibling.setAttribute("aria-hidden", "true");
138
+ } else if (stateMap.has(sibling)) {
139
+ const original = stateMap.get(sibling);
140
+ if (original === null) {
141
+ sibling.removeAttribute("aria-hidden");
142
+ } else {
143
+ sibling.setAttribute("aria-hidden", original);
144
+ }
145
+ stateMap.delete(sibling);
146
+ }
147
+ }
148
+ });
149
+ };
150
+ exports.setAriaHiddenForSiblings = setAriaHiddenForSiblings;
108
151
  const setFocusOnSendBox = () => {
109
152
  const sendBoxSelector = "textarea[data-id=\"webchat-sendbox-input\"]";
110
153
  setFocusOnElement(sendBoxSelector);
@@ -115,6 +158,41 @@ const setFocusOnElement = selector => {
115
158
  element === null || element === void 0 ? void 0 : element.focus();
116
159
  };
117
160
  exports.setFocusOnElement = setFocusOnElement;
161
+ const IMMEDIATE_ANNOUNCEMENT_REGION_ID = "oc-lcw-immediate-announcement";
162
+
163
+ // Announces a message to screen readers via an aria-live="assertive" region
164
+ // attached to document.body — outside the chat widget's DOM subtree — so the
165
+ // screen reader does not have to traverse chat content to reach it.
166
+ const announceMessageImmediately = message => {
167
+ if (!message || typeof document === "undefined") {
168
+ return;
169
+ }
170
+ let region = document.getElementById(IMMEDIATE_ANNOUNCEMENT_REGION_ID);
171
+ if (!region) {
172
+ region = document.createElement("div");
173
+ region.id = IMMEDIATE_ANNOUNCEMENT_REGION_ID;
174
+ region.setAttribute("aria-live", "assertive");
175
+ region.setAttribute("role", "alert");
176
+ region.setAttribute("aria-atomic", "true");
177
+ region.style.position = "absolute";
178
+ region.style.width = "1px";
179
+ region.style.height = "1px";
180
+ region.style.overflow = "hidden";
181
+ region.style.clip = "rect(0 0 0 0)";
182
+ region.style.clipPath = "inset(50%)";
183
+ region.style.whiteSpace = "nowrap";
184
+ document.body.appendChild(region);
185
+ }
186
+ region.textContent = "";
187
+ // Re-set on the next tick so screen readers detect the change even when
188
+ // the same message is announced twice in a row.
189
+ setTimeout(() => {
190
+ if (region) {
191
+ region.textContent = message;
192
+ }
193
+ }, 50);
194
+ };
195
+ exports.announceMessageImmediately = announceMessageImmediately;
118
196
  const escapeHtml = inputString => {
119
197
  const entityMap = {
120
198
  "<": "&lt;",
@@ -478,7 +556,7 @@ const setOcUserAgent = chatSDK => {
478
556
  // eslint-disable-line @typescript-eslint/no-explicit-any
479
557
  if ((_chatSDK$OCClient = chatSDK.OCClient) !== null && _chatSDK$OCClient !== void 0 && _chatSDK$OCClient.ocUserAgent && !((_chatSDK$OCClient2 = chatSDK.OCClient) !== null && _chatSDK$OCClient2 !== void 0 && _chatSDK$OCClient2.ocUserAgent.join(" ").includes("omnichannel-chat-widget/"))) {
480
558
  try {
481
- const version = require("../../../package.json").version; // eslint-disable-line @typescript-eslint/no-var-requires
559
+ const version = require("../../package.json").version; // eslint-disable-line @typescript-eslint/no-var-requires
482
560
  const userAgent = `omnichannel-chat-widget/${version}`;
483
561
  chatSDK.OCClient.ocUserAgent = [userAgent, ...chatSDK.OCClient.ocUserAgent];
484
562
  } catch (error) {
@@ -519,4 +597,15 @@ exports.getCustomEventValue = getCustomEventValue;
519
597
  function isEndConversationDueToOverflowActivity(activity) {
520
598
  var _activity$channelData, _activity$channelData2;
521
599
  return (activity === null || activity === void 0 ? void 0 : (_activity$channelData = activity.channelData) === null || _activity$channelData === void 0 ? void 0 : _activity$channelData.tags) && Array.isArray(activity === null || activity === void 0 ? void 0 : (_activity$channelData2 = activity.channelData) === null || _activity$channelData2 === void 0 ? void 0 : _activity$channelData2.tags) && activity.channelData.tags.includes(_Constants.Constants.EndConversationDueToOverflow);
600
+ }
601
+
602
+ /**
603
+ * Parses a value that can be boolean or string ("true"/"false") into a boolean.
604
+ * Handles null/undefined by returning false.
605
+ *
606
+ * @param value - The value to parse (can be boolean, string, null, or undefined)
607
+ * @returns true if value is true or "true" (case-insensitive), false otherwise
608
+ */
609
+ function parseBooleanFromConfig(value) {
610
+ return value === true || (value === null || value === void 0 ? void 0 : value.toString().toLowerCase()) === "true";
522
611
  }
@@ -44,7 +44,7 @@ const CitationPaneStateful = props => {
44
44
 
45
45
  // Initial focus pattern (mirrors ConfirmationPaneStateful): focus first focusable element (will re-attempt after visibility becomes true)
46
46
  (0, _react.useEffect)(() => {
47
- (0, _utils.preventFocusToMoveOutOfElement)(controlId);
47
+ const cleanup = (0, _utils.preventFocusToMoveOutOfElement)(controlId);
48
48
  const focusableElements = (0, _utils.findAllFocusableElement)(`#${controlId}`);
49
49
  requestAnimationFrame(() => {
50
50
  if (focusableElements && focusableElements.length > 0 && focusableElements[0]) {
@@ -62,6 +62,13 @@ const CitationPaneStateful = props => {
62
62
  Event: _TelemetryConstants.TelemetryEvent.UXCitationPaneCompleted,
63
63
  ElapsedTimeInMilliseconds: uiTimer.milliSecondsElapsed
64
64
  });
65
+ return () => {
66
+ // internal tracking: restore parent tab indices on unmount so focus
67
+ // can escape the widget even if the pane is dismissed by an
68
+ // external state change rather than a user button click.
69
+ (0, _utils.setTabIndices)(elements, initialTabIndexMap, true);
70
+ cleanup();
71
+ };
65
72
  }, []);
66
73
 
67
74
  // Retry focus once pane is actually visible (isReady) in case initial attempt occurred while wrapper was visibility:hidden
@@ -82,7 +82,7 @@ const ConfirmationPaneStateful = props => {
82
82
 
83
83
  // Move focus to the first button
84
84
  (0, _react.useEffect)(() => {
85
- (0, _utils.preventFocusToMoveOutOfElement)(controlProps.id);
85
+ const cleanup = (0, _utils.preventFocusToMoveOutOfElement)(controlProps.id);
86
86
  const focusableElements = (0, _utils.findAllFocusableElement)(`#${controlProps.id}`);
87
87
  requestAnimationFrame(() => {
88
88
  if (focusableElements && focusableElements.length > 0 && focusableElements[0]) {
@@ -100,6 +100,17 @@ const ConfirmationPaneStateful = props => {
100
100
  Event: _TelemetryConstants.TelemetryEvent.UXConfirmationPaneCompleted,
101
101
  ElapsedTimeInMilliseconds: uiTimer.milliSecondsElapsed
102
102
  });
103
+ return () => {
104
+ // internal tracking: when the confirmation pane unmounts (page reload,
105
+ // parent state change, or any path that bypasses onConfirm /
106
+ // onCancel) the tab indices that were forced to -1 on sibling
107
+ // focusable elements must be restored, otherwise Tab order
108
+ // remains broken and focus can be trapped inside the widget.
109
+ // setTabIndices is a no-op when initialTabIndexMap is already
110
+ // empty (onConfirm / onCancel already restored).
111
+ (0, _utils.setTabIndices)(elements, initialTabIndexMap, true);
112
+ cleanup();
113
+ };
103
114
  }, []);
104
115
  return /*#__PURE__*/_react.default.createElement(_react.default.Fragment, null, /*#__PURE__*/_react.default.createElement(_DimLayer.DimLayer, {
105
116
  brightness: (controlProps === null || controlProps === void 0 ? void 0 : controlProps.brightnessValueOnDim) ?? "0.2"
@@ -35,16 +35,23 @@ const EmailTranscriptPaneStateful = props => {
35
35
  const [state, dispatch] = (0, _useChatContextStore.default)();
36
36
  const [facadeChatSDK] = (0, _useFacadeChatSDKStore.default)();
37
37
  const [initialEmail, setInitialEmail] = (0, _react.useState)("");
38
- const closeEmailTranscriptPane = () => {
38
+ // restoreFocus=false is used on the submit path: the notification banner
39
+ // (success or error) takes focus via NotificationHandler.setFocusOnNotificationCloseButton,
40
+ // so an intermediate restore to the chat-widget shell would otherwise cause SRs to
41
+ // announce "Enter <widget>" in between the dialog and the banner.
42
+ const closeEmailTranscriptPane = function () {
43
+ let restoreFocus = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : true;
39
44
  dispatch({
40
45
  type: _LiveChatWidgetActionType.LiveChatWidgetActionType.SET_SHOW_EMAIL_TRANSCRIPT_PANE,
41
46
  payload: false
42
47
  });
43
- const previousFocusedElementId = state.appStates.previousElementIdOnFocusBeforeModalOpen;
44
- if (previousFocusedElementId) {
45
- (0, _utils.setFocusOnElement)("#" + previousFocusedElementId);
46
- } else {
47
- (0, _utils.setFocusOnSendBox)();
48
+ if (restoreFocus) {
49
+ const previousFocusedElementId = state.appStates.previousElementIdOnFocusBeforeModalOpen;
50
+ if (previousFocusedElementId) {
51
+ (0, _utils.setFocusOnElement)("#" + previousFocusedElementId);
52
+ } else {
53
+ (0, _utils.setFocusOnSendBox)();
54
+ }
48
55
  }
49
56
  dispatch({
50
57
  type: _LiveChatWidgetActionType.LiveChatWidgetActionType.SET_PREVIOUS_FOCUSED_ELEMENT_ID,
@@ -55,23 +62,31 @@ const EmailTranscriptPaneStateful = props => {
55
62
  const onSend = (0, _react.useCallback)(async email => {
56
63
  var _state$domainStates;
57
64
  const liveChatContext = state === null || state === void 0 ? void 0 : (_state$domainStates = state.domainStates) === null || _state$domainStates === void 0 ? void 0 : _state$domainStates.liveChatContext;
58
- closeEmailTranscriptPane();
65
+ closeEmailTranscriptPane(false);
59
66
  const chatTranscriptBody = {
60
67
  emailAddress: email,
61
68
  attachmentMessage: (props === null || props === void 0 ? void 0 : props.attachmentMessage) ?? "The following attachment was uploaded during the conversation:"
62
69
  };
63
70
  try {
64
- var _state$domainStates2, _state$domainStates2$;
71
+ var _state$domainStates2, _state$domainStates2$, _state$domainStates3, _state$domainStates3$;
65
72
  await (facadeChatSDK === null || facadeChatSDK === void 0 ? void 0 : facadeChatSDK.emailLiveChatTranscript(chatTranscriptBody, {
66
73
  liveChatContext
67
74
  }));
68
- _NotificationHandler.NotificationHandler.notifySuccess(_NotificationScenarios.NotificationScenarios.EmailAddressSaved, (state === null || state === void 0 ? void 0 : (_state$domainStates2 = state.domainStates) === null || _state$domainStates2 === void 0 ? void 0 : (_state$domainStates2$ = _state$domainStates2.middlewareLocalizedTexts) === null || _state$domainStates2$ === void 0 ? void 0 : _state$domainStates2$.MIDDLEWARE_BANNER_FILE_EMAIL_ADDRESS_RECORDED_SUCCESS) ?? (_defaultMiddlewareLocalizedTexts.defaultMiddlewareLocalizedTexts === null || _defaultMiddlewareLocalizedTexts.defaultMiddlewareLocalizedTexts === void 0 ? void 0 : _defaultMiddlewareLocalizedTexts.defaultMiddlewareLocalizedTexts.MIDDLEWARE_BANNER_FILE_EMAIL_ADDRESS_RECORDED_SUCCESS));
75
+ const successMessage = (state === null || state === void 0 ? void 0 : (_state$domainStates2 = state.domainStates) === null || _state$domainStates2 === void 0 ? void 0 : (_state$domainStates2$ = _state$domainStates2.middlewareLocalizedTexts) === null || _state$domainStates2$ === void 0 ? void 0 : _state$domainStates2$.MIDDLEWARE_BANNER_FILE_EMAIL_ADDRESS_RECORDED_SUCCESS) ?? (_defaultMiddlewareLocalizedTexts.defaultMiddlewareLocalizedTexts === null || _defaultMiddlewareLocalizedTexts.defaultMiddlewareLocalizedTexts === void 0 ? void 0 : _defaultMiddlewareLocalizedTexts.defaultMiddlewareLocalizedTexts.MIDDLEWARE_BANNER_FILE_EMAIL_ADDRESS_RECORDED_SUCCESS);
76
+ // Announce from a live region at document.body level so the
77
+ // screen reader speaks the confirmation immediately, without
78
+ // traversing the chat transcript on the way to the banner.
79
+ // Prefix with the explicit state word so SR users hear the outcome
80
+ // (visual users already see a success icon on the banner).
81
+ const successSrPrefix = (state === null || state === void 0 ? void 0 : (_state$domainStates3 = state.domainStates) === null || _state$domainStates3 === void 0 ? void 0 : (_state$domainStates3$ = _state$domainStates3.middlewareLocalizedTexts) === null || _state$domainStates3$ === void 0 ? void 0 : _state$domainStates3$.MIDDLEWARE_SR_PREFIX_SUCCESS) ?? _defaultMiddlewareLocalizedTexts.defaultMiddlewareLocalizedTexts.MIDDLEWARE_SR_PREFIX_SUCCESS;
82
+ (0, _utils.announceMessageImmediately)(`${successSrPrefix}${successMessage}`);
83
+ _NotificationHandler.NotificationHandler.notifySuccess(_NotificationScenarios.NotificationScenarios.EmailAddressSaved, successMessage);
69
84
  _TelemetryHelper.TelemetryHelper.logActionEventToAllTelemetry(_TelemetryConstants.LogLevel.INFO, {
70
85
  Event: _TelemetryConstants.TelemetryEvent.EmailTranscriptSent,
71
86
  Description: "Transcript sent to email successfully."
72
87
  });
73
88
  } catch (ex) {
74
- var _state$domainStates3, _state$domainStates3$;
89
+ var _state$domainStates4, _state$domainStates4$, _state$domainStates5, _state$domainStates5$;
75
90
  _TelemetryHelper.TelemetryHelper.logActionEventToAllTelemetry(_TelemetryConstants.LogLevel.ERROR, {
76
91
  Event: _TelemetryConstants.TelemetryEvent.EmailTranscriptFailed,
77
92
  Description: "Email transcript failed.",
@@ -79,8 +94,11 @@ const EmailTranscriptPaneStateful = props => {
79
94
  exception: ex
80
95
  }
81
96
  });
82
- const message = (0, _utils.formatTemplateString)((state === null || state === void 0 ? void 0 : (_state$domainStates3 = state.domainStates) === null || _state$domainStates3 === void 0 ? void 0 : (_state$domainStates3$ = _state$domainStates3.middlewareLocalizedTexts) === null || _state$domainStates3$ === void 0 ? void 0 : _state$domainStates3$.MIDDLEWARE_BANNER_FILE_EMAIL_ADDRESS_RECORDED_ERROR) ?? _defaultMiddlewareLocalizedTexts.defaultMiddlewareLocalizedTexts.MIDDLEWARE_BANNER_FILE_EMAIL_ADDRESS_RECORDED_ERROR, [email]);
83
- _NotificationHandler.NotificationHandler.notifyError(_NotificationScenarios.NotificationScenarios.EmailTranscriptError, (props === null || props === void 0 ? void 0 : props.bannerMessageOnError) ?? message);
97
+ const message = (0, _utils.formatTemplateString)((state === null || state === void 0 ? void 0 : (_state$domainStates4 = state.domainStates) === null || _state$domainStates4 === void 0 ? void 0 : (_state$domainStates4$ = _state$domainStates4.middlewareLocalizedTexts) === null || _state$domainStates4$ === void 0 ? void 0 : _state$domainStates4$.MIDDLEWARE_BANNER_FILE_EMAIL_ADDRESS_RECORDED_ERROR) ?? _defaultMiddlewareLocalizedTexts.defaultMiddlewareLocalizedTexts.MIDDLEWARE_BANNER_FILE_EMAIL_ADDRESS_RECORDED_ERROR, [email]);
98
+ const bannerMessage = (props === null || props === void 0 ? void 0 : props.bannerMessageOnError) ?? message;
99
+ const errorSrPrefix = (state === null || state === void 0 ? void 0 : (_state$domainStates5 = state.domainStates) === null || _state$domainStates5 === void 0 ? void 0 : (_state$domainStates5$ = _state$domainStates5.middlewareLocalizedTexts) === null || _state$domainStates5$ === void 0 ? void 0 : _state$domainStates5$.MIDDLEWARE_SR_PREFIX_ERROR) ?? _defaultMiddlewareLocalizedTexts.defaultMiddlewareLocalizedTexts.MIDDLEWARE_SR_PREFIX_ERROR;
100
+ (0, _utils.announceMessageImmediately)(`${errorSrPrefix}${bannerMessage}`);
101
+ _NotificationHandler.NotificationHandler.notifyError(_NotificationScenarios.NotificationScenarios.EmailTranscriptError, bannerMessage);
84
102
  }
85
103
  }, [props.attachmentMessage, props.bannerMessageOnError, facadeChatSDK, state.domainStates.liveChatContext]);
86
104
  const controlProps = {
@@ -103,7 +121,7 @@ const EmailTranscriptPaneStateful = props => {
103
121
 
104
122
  // Move focus to the first button
105
123
  (0, _react.useEffect)(() => {
106
- (0, _utils.preventFocusToMoveOutOfElement)(controlProps.id);
124
+ const cleanup = (0, _utils.preventFocusToMoveOutOfElement)(controlProps.id);
107
125
  const focusableElements = (0, _utils.findAllFocusableElement)(`#${controlProps.id}`);
108
126
  if (focusableElements) {
109
127
  focusableElements[0].focus();
@@ -118,6 +136,11 @@ const EmailTranscriptPaneStateful = props => {
118
136
  Event: _TelemetryConstants.TelemetryEvent.UXEmailTranscriptPaneCompleted,
119
137
  ElapsedTimeInMilliseconds: uiTimer.milliSecondsElapsed
120
138
  });
139
+ return () => {
140
+ // internal tracking: restore parent tab indices on unmount.
141
+ (0, _utils.setTabIndices)(elements, initialTabIndexMap, true);
142
+ cleanup();
143
+ };
121
144
  }, [initialEmail]);
122
145
  return /*#__PURE__*/_react.default.createElement(_react.default.Fragment, null, /*#__PURE__*/_react.default.createElement(_DimLayer.DimLayer, {
123
146
  brightness: (controlProps === null || controlProps === void 0 ? void 0 : controlProps.brightnessValueOnDim) ?? "0.2"
@@ -19,11 +19,12 @@ function _possibleConstructorReturn(self, call) { if (call && (typeof call === "
19
19
  function _assertThisInitialized(self) { if (self === void 0) { throw new ReferenceError("this hasn't been initialised - super() hasn't been called"); } return self; }
20
20
  function _isNativeReflectConstruct() { if (typeof Reflect === "undefined" || !Reflect.construct) return false; if (Reflect.construct.sham) return false; if (typeof Proxy === "function") return true; try { Boolean.prototype.valueOf.call(Reflect.construct(Boolean, [], function () {})); return true; } catch (e) { return false; } }
21
21
  function _getPrototypeOf(o) { _getPrototypeOf = Object.setPrototypeOf ? Object.getPrototypeOf.bind() : function _getPrototypeOf(o) { return o.__proto__ || Object.getPrototypeOf(o); }; return _getPrototypeOf(o); }
22
+ // eslint-disable-next-line @typescript-eslint/ban-types
22
23
  const RenderChildrenFunction = _ref => {
23
24
  let {
24
25
  children
25
26
  } = _ref;
26
- return typeof children === 'function' ? children() : children;
27
+ return typeof children === "function" ? children() : children;
27
28
  };
28
29
  let ErrorBoundary = /*#__PURE__*/function (_Component) {
29
30
  _inherits(ErrorBoundary, _Component);
@@ -35,8 +35,16 @@ const LiveChatWidget = props => {
35
35
  throw new Error("chatConfig is required");
36
36
  }
37
37
 
38
+ // Check configuration flags
38
39
  // eslint-disable-next-line @typescript-eslint/no-explicit-any
39
- const isAuthenticatedChat = !!((_props$chatConfig = props.chatConfig) !== null && _props$chatConfig !== void 0 && (_props$chatConfig$Liv = _props$chatConfig.LiveChatConfigAuthSettings) !== null && _props$chatConfig$Liv !== void 0 && _props$chatConfig$Liv.msdyn_javascriptclientfunction) || (0, _liveChatConfigUtils.isPersistentChatEnabled)((_props$chatConfig2 = props.chatConfig) === null || _props$chatConfig2 === void 0 ? void 0 : (_props$chatConfig2$Li = _props$chatConfig2.LiveWSAndLiveChatEngJoin) === null || _props$chatConfig2$Li === void 0 ? void 0 : _props$chatConfig2$Li.msdyn_conversationmode);
40
+ const hasAuthClientFn = !!((_props$chatConfig = props.chatConfig) !== null && _props$chatConfig !== void 0 && (_props$chatConfig$Liv = _props$chatConfig.LiveChatConfigAuthSettings) !== null && _props$chatConfig$Liv !== void 0 && _props$chatConfig$Liv.msdyn_javascriptclientfunction);
41
+ const persistentChatEnabled = (0, _liveChatConfigUtils.isPersistentChatEnabled)((_props$chatConfig2 = props.chatConfig) === null || _props$chatConfig2 === void 0 ? void 0 : (_props$chatConfig2$Li = _props$chatConfig2.LiveWSAndLiveChatEngJoin) === null || _props$chatConfig2$Li === void 0 ? void 0 : _props$chatConfig2$Li.msdyn_conversationmode);
42
+
43
+ // isAuthenticatedChat determines if FacadeChatSDK should require authentication:
44
+ // REGULAR AUTH FLOW (config-based):
45
+ // - Persistent chat enabled ? always authenticated
46
+ // - Auth settings exist ? authenticated from start
47
+ const isAuthenticatedChat = persistentChatEnabled || hasAuthClientFn;
40
48
  if (!facadeChatSDK) {
41
49
  var _props$mock;
42
50
  setFacadeChatSDK(new _FacadeChatSDK.FacadeChatSDK({
@@ -44,7 +44,7 @@ const extractSasUrl = async attachment => {
44
44
  }
45
45
  return sasUrl;
46
46
  };
47
- const fetchBotAuthConfig = async (retries, interval) => {
47
+ const fetchBotAuthConfig = async (retries, interval, fallback) => {
48
48
  _TelemetryHelper.TelemetryHelper.logLoadingEvent(_TelemetryConstants.LogLevel.INFO, {
49
49
  Event: _TelemetryConstants.TelemetryEvent.SetBotAuthProviderFetchConfig
50
50
  });
@@ -60,13 +60,23 @@ const fetchBotAuthConfig = async (retries, interval) => {
60
60
  });
61
61
  if (retries === 1) {
62
62
  // Base Case
63
- throw new Error();
63
+ if (response !== undefined) {
64
+ return response;
65
+ }
66
+ if (fallback !== undefined) {
67
+ _TelemetryHelper.TelemetryHelper.logLoadingEvent(_TelemetryConstants.LogLevel.WARN, {
68
+ Event: _TelemetryConstants.TelemetryEvent.SetBotAuthProviderNotFound,
69
+ Description: `Failed to fetch bot auth config after maximum retries. Using fallback value: ${fallback}`
70
+ });
71
+ return fallback;
72
+ }
73
+ throw new Error("Failed to fetch bot auth config after maximum retries");
64
74
  }
65
75
  await delay(interval);
66
76
  if (response !== undefined) {
67
77
  return response;
68
78
  }
69
- return await fetchBotAuthConfig(--retries, interval);
79
+ return await fetchBotAuthConfig(--retries, interval, fallback);
70
80
  };
71
81
  let BotAuthActivitySubscriber = /*#__PURE__*/function () {
72
82
  function BotAuthActivitySubscriber() {
@@ -76,6 +86,7 @@ let BotAuthActivitySubscriber = /*#__PURE__*/function () {
76
86
  _defineProperty(this, "signInCardSeen", void 0);
77
87
  _defineProperty(this, "fetchBotAuthConfigRetries", void 0);
78
88
  _defineProperty(this, "fetchBotAuthConfigRetryInterval", void 0);
89
+ _defineProperty(this, "fallbackShowSignInCard", void 0);
79
90
  this.signInCardSeen = new Set();
80
91
  this.fetchBotAuthConfigRetries = 3;
81
92
  this.fetchBotAuthConfigRetryInterval = 1000;
@@ -85,6 +96,11 @@ let BotAuthActivitySubscriber = /*#__PURE__*/function () {
85
96
  if (optionalParams.fetchBotAuthConfigRetryInterval) {
86
97
  this.fetchBotAuthConfigRetryInterval = optionalParams.fetchBotAuthConfigRetryInterval;
87
98
  }
99
+ this.fallbackShowSignInCard = optionalParams.fallbackShowSignInCard;
100
+ _TelemetryHelper.TelemetryHelper.logLoadingEvent(_TelemetryConstants.LogLevel.INFO, {
101
+ Event: _TelemetryConstants.TelemetryEvent.SetBotAuthProviderFetchConfig,
102
+ Description: `BotAuthActivitySubscriber initialized with fallbackShowSignInCard: ${optionalParams.fallbackShowSignInCard}`
103
+ });
88
104
  }
89
105
  _createClass(BotAuthActivitySubscriber, [{
90
106
  key: "applicable",
@@ -129,7 +145,7 @@ let BotAuthActivitySubscriber = /*#__PURE__*/function () {
129
145
  _omnichannelChatComponents.BroadcastService.postMessage(event);
130
146
  }
131
147
  try {
132
- const response = await fetchBotAuthConfig(this.fetchBotAuthConfigRetries, this.fetchBotAuthConfigRetryInterval);
148
+ const response = await fetchBotAuthConfig(this.fetchBotAuthConfigRetries, this.fetchBotAuthConfigRetryInterval, this.fallbackShowSignInCard);
133
149
  if (response === false) {
134
150
  _TelemetryHelper.TelemetryHelper.logLoadingEvent(_TelemetryConstants.LogLevel.INFO, {
135
151
  Event: _TelemetryConstants.TelemetryEvent.SetBotAuthProviderHideCard
@@ -140,9 +156,10 @@ let BotAuthActivitySubscriber = /*#__PURE__*/function () {
140
156
  });
141
157
  return activity;
142
158
  }
143
- } catch {
159
+ } catch (e) {
144
160
  _TelemetryHelper.TelemetryHelper.logLoadingEvent(_TelemetryConstants.LogLevel.INFO, {
145
- Event: _TelemetryConstants.TelemetryEvent.SetBotAuthProviderNotFound
161
+ Event: _TelemetryConstants.TelemetryEvent.SetBotAuthProviderNotFound,
162
+ ExceptionDetails: e instanceof Error ? e.message : JSON.stringify(e)
146
163
  });
147
164
  //this is to ensure listener continues waiting for response
148
165
  if (this.signInCardSeen.has(signInId)) {
@@ -10,6 +10,7 @@ var ChatWidgetEvents;
10
10
  ChatWidgetEvents["FETCH_PERSISTENT_CHAT_HISTORY"] = "CHAT_WIDGET/FETCH_PERSISTENT_CHAT_HISTORY";
11
11
  ChatWidgetEvents["NO_MORE_HISTORY_AVAILABLE"] = "CHAT_WIDGET/NO_MORE_HISTORY_AVAILABLE";
12
12
  ChatWidgetEvents["HISTORY_LOAD_ERROR"] = "CHAT_WIDGET/HISTORY_LOAD_ERROR";
13
+ ChatWidgetEvents["HISTORY_BATCH_LOADED"] = "CHAT_WIDGET/HISTORY_BATCH_LOADED";
13
14
  })(ChatWidgetEvents || (ChatWidgetEvents = {}));
14
15
  var _default = ChatWidgetEvents;
15
16
  exports.default = _default;
@@ -133,6 +133,12 @@ let PersistentConversationHandler = /*#__PURE__*/function () {
133
133
  }
134
134
  const messagesDescOrder = (_ref = [...messages]) === null || _ref === void 0 ? void 0 : _ref.reverse();
135
135
  this.processHistoryMessages(messagesDescOrder);
136
+
137
+ // Signal that a batch of history messages has been added to the store.
138
+ // LazyLoadActivity subscribes to this to apply scroll anchoring after render.
139
+ (0, _dispatchCustomEvent.default)(_ChatWidgetEvents.default.HISTORY_BATCH_LOADED, {
140
+ messageCount: messages.length
141
+ });
136
142
  _TelemetryHelper.TelemetryHelper.logActionEvent(_TelemetryConstants.LogLevel.INFO, {
137
143
  Event: _TelemetryConstants.TelemetryEvent.LCWPersistentHistoryPullCompleted,
138
144
  Description: "History pull completed successfully",
@@ -241,6 +247,9 @@ let PersistentConversationHandler = /*#__PURE__*/function () {
241
247
  value: function processMessageToActivity(message) {
242
248
  try {
243
249
  const activity = (0, _convertPersistentChatHistoryMessageToActivity.default)(message);
250
+ if (!activity) {
251
+ return null;
252
+ }
244
253
  activity.id = activity.id || `activity-${this.count}`;
245
254
  activity.channelData = {
246
255
  ...activity.channelData,