@microsoft/omnichannel-chat-sdk 1.11.9-main.b0a2bb8 → 1.11.9-main.d767cc8

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 (52) hide show
  1. package/README.md +240 -5
  2. package/lib/OmnichannelChatSDK.d.ts +42 -0
  3. package/lib/OmnichannelChatSDK.js +438 -93
  4. package/lib/OmnichannelChatSDK.js.map +1 -1
  5. package/lib/core/ChatSDKError.d.ts +13 -1
  6. package/lib/core/ChatSDKError.js +12 -0
  7. package/lib/core/ChatSDKError.js.map +1 -1
  8. package/lib/core/ChatSDKExceptionDetails.d.ts +6 -0
  9. package/lib/core/StartChatOptionalParams.d.ts +11 -0
  10. package/lib/core/messaging/ACSClient.d.ts +7 -0
  11. package/lib/core/messaging/ACSClient.js +216 -12
  12. package/lib/core/messaging/ACSClient.js.map +1 -1
  13. package/lib/core/messaging/OmnichannelStreamingMessage.d.ts +13 -0
  14. package/lib/core/messaging/OmnichannelStreamingMessage.js +3 -0
  15. package/lib/core/messaging/OmnichannelStreamingMessage.js.map +1 -0
  16. package/lib/core/messaging/OnStreamingMessageOptionalParams.d.ts +8 -0
  17. package/lib/core/messaging/OnStreamingMessageOptionalParams.js +3 -0
  18. package/lib/core/messaging/OnStreamingMessageOptionalParams.js.map +1 -0
  19. package/lib/core/messaging/PolicyViolation.d.ts +8 -0
  20. package/lib/core/messaging/PolicyViolation.js +3 -0
  21. package/lib/core/messaging/PolicyViolation.js.map +1 -0
  22. package/lib/core/messaging/StreamingMetadata.d.ts +11 -0
  23. package/lib/core/messaging/StreamingMetadata.js +3 -0
  24. package/lib/core/messaging/StreamingMetadata.js.map +1 -0
  25. package/lib/index.d.ts +5 -1
  26. package/lib/index.js.map +1 -1
  27. package/lib/telemetry/MessageSource.d.ts +1 -0
  28. package/lib/telemetry/MessageSource.js +1 -0
  29. package/lib/telemetry/MessageSource.js.map +1 -1
  30. package/lib/telemetry/TelemetryEvent.d.ts +24 -1
  31. package/lib/telemetry/TelemetryEvent.js +24 -0
  32. package/lib/telemetry/TelemetryEvent.js.map +1 -1
  33. package/lib/tsconfig.tsbuildinfo +1 -1
  34. package/lib/utils/createOmnichannelMessage.js +27 -1
  35. package/lib/utils/createOmnichannelMessage.js.map +1 -1
  36. package/lib/utils/createOmnichannelStreamingMessage.d.ts +14 -0
  37. package/lib/utils/createOmnichannelStreamingMessage.js +106 -0
  38. package/lib/utils/createOmnichannelStreamingMessage.js.map +1 -0
  39. package/lib/utils/errorClassifier.d.ts +25 -0
  40. package/lib/utils/errorClassifier.js +75 -0
  41. package/lib/utils/errorClassifier.js.map +1 -0
  42. package/lib/utils/exceptionThrowers.d.ts +38 -4
  43. package/lib/utils/exceptionThrowers.js +25 -8
  44. package/lib/utils/exceptionThrowers.js.map +1 -1
  45. package/lib/utils/printers/MessagePrinterFactory.d.ts +3 -2
  46. package/lib/utils/printers/MessagePrinterFactory.js +6 -0
  47. package/lib/utils/printers/MessagePrinterFactory.js.map +1 -1
  48. package/lib/utils/printers/StreamingMessagePrinter.d.ts +5 -0
  49. package/lib/utils/printers/StreamingMessagePrinter.js +33 -0
  50. package/lib/utils/printers/StreamingMessagePrinter.js.map +1 -0
  51. package/lib/utils/printers/types/MessageType.d.ts +2 -1
  52. package/package.json +6 -6
package/README.md CHANGED
@@ -5,9 +5,9 @@
5
5
  ![Release CI](https://github.com/microsoft/omnichannel-chat-sdk/workflows/Release%20CI/badge.svg)
6
6
  ![npm](https://img.shields.io/npm/dm/@microsoft/omnichannel-chat-sdk)
7
7
 
8
- > ❗ We recommend using official release versions in production as listed [here](#releases). Support will be provided only on official versions.
9
-
10
- > 📢 Try out our new React component library [omnichannel-chat-widget](https://github.com/microsoft/omnichannel-chat-widget) with Chat SDK
8
+ > [!IMPORTANT]
9
+ > * We recommend using official release versions in production as listed [here](#releases). Support will be provided only on official versions.
10
+ > * Microsoft provides this SDK to ensure a scaleable and secure use of our platform. Do not directly access the APIs used in this repository — you may experience breaking changes, and we will not be able to provide support for any issues.
11
11
 
12
12
  Headless Chat SDK to build your own chat widget against Dynamics 365 Omnichannel Services.
13
13
 
@@ -44,6 +44,9 @@ Please make sure you have a chat widget configured before using this package or
44
44
  - [Create Chat Adapter](#create-chat-adapter)
45
45
  - [Get Voice & Video Calling](#get-voice--video-calling)
46
46
  - [Get Post Chat Survey Context](#get-post-chat-survey-context)
47
+ - [Get Persistent Chat History](#get-persistent-chat-history)
48
+ - [Send Read Receipt](#send-read-receipt)
49
+ - [Get Unread Message Count](#get-unread-message-count)
47
50
  - [Common Scenarios](#common-scenarios)
48
51
  - [Using BotFramework-WebChat](#using-botframework-webchat)
49
52
  - [Escalation to Voice & Video](#escalation-to-voice--video)
@@ -52,6 +55,7 @@ Please make sure you have a chat widget configured before using this package or
52
55
  - [Reconnect to existing Chat](#reconnect-to-existing-chat)
53
56
  - [Authenticated Chat](#authenticated-chat)
54
57
  - [Persistent Chat](#persistent-chat)
58
+ - [Persistent Chat History](#persistent-chat-history)
55
59
  - [Chat Reconnect with Authenticated User](#chat-reconnect-with-authenticated-user)
56
60
  - [Chat Reconnect with Unauthenticated User](#chat-reconnect-with-unauthenticated-user)
57
61
  - [Best Practices for Chat Session Management: Handling Disconnections and Network Instabilit(#best-practices-for-chat-session-management:-handling-disconnections-and-network-instability)
@@ -104,9 +108,9 @@ Omnichannel offers a live chat widget (LCW) by default. You can use the Chat SDK
104
108
 
105
109
  New releases are published on a regular basis to ensure the product quality.
106
110
 
107
- for a detailed tracking of the releases, please refer to the [Changelog document](https://github.com/microsoft/omnichannel-chat-sdk/blob/main/CHANGELOG.md)
111
+ For a detailed tracking of the releases, please refer to the [Changelog document](https://github.com/microsoft/omnichannel-chat-sdk/blob/main/CHANGELOG.md)
108
112
 
109
- _**Important Note:**_ Versions below 1.11.0 will not be supported after November 1st, 2025. Please update to recent versions to ensure you have the latest features and bug fixes.
113
+ _**Important Note:**_ Versions below 1.11.0 are no longer supported after November 1st, 2025. Please update to recent versions to ensure you have the latest features and bug fixes.
110
114
 
111
115
 
112
116
  | Version | Docs | Release Date | End of Support | Deprecated |
@@ -579,6 +583,24 @@ It gets the participant type that should be used for the survey and both the def
579
583
  const postChatSurveyContext = await chatSDK.getPostChatSurveyContext();
580
584
  ```
581
585
 
586
+ ### Get Persistent Chat History
587
+
588
+ It fetches paginated chat history from previous persistent chat conversations for authenticated users. Returns messages in chronological order along with a pagination token to fetch the next page.
589
+
590
+ > :warning: Requires **persistent chat** to be enabled and the user must be **authenticated**.
591
+
592
+ ```ts
593
+ const optionalParams = {
594
+ pageSize: 25, // Number of messages per page (optional)
595
+ pageToken: '' // Token from a previous response to fetch the next page (optional, omit for first call)
596
+ };
597
+
598
+ const response = await chatSDK.getPersistentChatHistory(optionalParams);
599
+
600
+ // response.chatMessages: PersistentChatHistoryMessage[] — Array of chat messages
601
+ // response.nextPageToken: string | null — Token to pass in the next call; null means no more history
602
+ ```
603
+
582
604
  ### Get Agent Availability
583
605
 
584
606
  It gets information on whether a queue is available, and whether there are agents available in that queue, as well as queue position and average wait time. This call only supports authenticated chat.
@@ -587,6 +609,25 @@ It gets information on whether a queue is available, and whether there are agent
587
609
  const agentAvailability = await chatSDK.getAgentAvailability();
588
610
  ```
589
611
 
612
+ ### Send Read Receipt
613
+
614
+ Logs a particular message (and all previous messages) as read by the user. Read indicators will appear for Contact Center Representatives and Admins in the Admin Center.
615
+
616
+ ```ts
617
+ await chatSDK.sendReadReceipt(messageId: string);
618
+ ```
619
+
620
+ ### Get Unread Message Count
621
+
622
+ Returns the number of unread messages in an authenticated persistent conversation. This call is **authenticated-only** — the user must be authenticated, otherwise an `UndefinedAuthToken` error is thrown.
623
+
624
+ ```ts
625
+ const response = await chatSDK.getUnreadMessageCount();
626
+
627
+ // response.unreadMessageCount: number — Number of unread messages in the conversation
628
+ // response.mostRecentUnreadMessage: object | null — The most recent unread message, or null if there are none
629
+ ```
630
+
590
631
  ## Common Scenarios
591
632
 
592
633
  ### Pre-Chat Survey
@@ -735,6 +776,200 @@ await chatSDK.initialize();
735
776
  // from this point, this acts like a persistent chat
736
777
  ```
737
778
 
779
+ ### Persistent Chat History
780
+
781
+ > See <https://docs.microsoft.com/en-us/dynamics365/customer-service/persistent-chat> on how to set up persistent chat
782
+
783
+ When persistent chat is enabled, you can retrieve the chat history from previous conversations using `getPersistentChatHistory()`. This method returns paginated results, allowing you to load history incrementally (e.g., as the user scrolls up).
784
+
785
+ > :warning: **Prerequisites:**
786
+ > - Persistent chat must be **enabled** in the admin portal (conversation mode set to Persistent Chat) and in the SDK config (`persistentChat.disable: false`)
787
+ > - The user must be **authenticated** (`getAuthToken` must be configured)
788
+ > - `chatSDK.initialize()` and `chatSDK.startChat()` must be called before fetching history
789
+ > - Chat history is available for up to **12 months**
790
+
791
+ #### Page Size
792
+
793
+ The `pageSize` parameter controls how many messages are returned per call.
794
+
795
+ | | Value |
796
+ | --- | --- |
797
+ | **Default** | `50` (used when `pageSize` is omitted) |
798
+ | **Minimum** | `1` |
799
+ | **Maximum** | `100` |
800
+
801
+ If `pageSize` is not provided, the backend defaults to **50**. Values outside the 1–100 range will be rejected with an error.
802
+
803
+ #### How Pagination Works
804
+
805
+ | Call | `pageToken` param | What happens |
806
+ | --- | --- | --- |
807
+ | **First call** | Omit or `undefined` | Fetches the most recent page of messages. The response includes `nextPageToken` if older messages exist. |
808
+ | **Subsequent calls** | Pass the `nextPageToken` from the previous response | Fetches the next (older) page. Again returns `nextPageToken` if more messages remain. |
809
+ | **Last page** | Pass the `nextPageToken` from the previous response | Returns the remaining messages. `nextPageToken` is `null`, indicating there are no more messages in the history. |
810
+
811
+ In short: keep passing the `nextPageToken` from each response into the next call until the backend returns `nextPageToken: null` — that signals the entire history has been retrieved.
812
+
813
+ #### Basic Usage
814
+
815
+ ```ts
816
+ const chatSDKConfig = {
817
+ persistentChat: {
818
+ disable: false,
819
+ tokenUpdateTime: 21600000
820
+ },
821
+ getAuthToken: async () => {
822
+ const response = await fetch("http://contosohelp.com/token");
823
+ if (response.ok) {
824
+ return await response.text();
825
+ }
826
+ else {
827
+ return null
828
+ }
829
+ }
830
+ }
831
+
832
+ const chatSDK = new OmnichannelChatSDK.OmnichannelChatSDK(omnichannelConfig, chatSDKConfig);
833
+ await chatSDK.initialize();
834
+
835
+ await chatSDK.startChat();
836
+
837
+ // Fetch the first page of chat history
838
+ const history = await chatSDK.getPersistentChatHistory({
839
+ pageSize: 25
840
+ });
841
+
842
+ if (history) {
843
+ // Render messages
844
+ history.chatMessages.forEach((message) => {
845
+ console.log(`[${message.createdDateTime}] ${message.content}`);
846
+ });
847
+
848
+ // Check if more history is available
849
+ if (history.nextPageToken) {
850
+ console.log("More history available");
851
+ }
852
+ }
853
+ ```
854
+
855
+ #### Pagination — Loading More History on Scroll Up
856
+
857
+ After the first call returns a `nextPageToken`, you can fetch older pages on demand — for example, each time the customer scrolls up in the chat window. The loop below shows fetching all remaining history, but in practice you would call `getPersistentChatHistory` once per scroll-up action, passing the `nextPageToken` from the previous response.
858
+
859
+ ```ts
860
+ // After the first call (Basic Usage above), save the nextPageToken
861
+ let pageToken: string | undefined = history?.nextPageToken ?? undefined;
862
+
863
+ // Example: fetch the next page when the customer scrolls up
864
+ const loadMoreHistory = async () => {
865
+ if (!pageToken) {
866
+ console.log("No more history to load");
867
+ return;
868
+ }
869
+
870
+ const response = await chatSDK.getPersistentChatHistory({
871
+ pageSize: 25,
872
+ pageToken
873
+ });
874
+
875
+ if (response && response.chatMessages.length > 0) {
876
+ // Render the older messages in the chat UI
877
+ response.chatMessages.forEach((message) => {
878
+ console.log(`[${message.createdDateTime}] ${message.content}`);
879
+ });
880
+
881
+ // Update the token for the next scroll-up action
882
+ pageToken = response.nextPageToken ?? undefined;
883
+ }
884
+ };
885
+
886
+ // Bind to your scroll-up event (e.g., user reaches the top of the chat container)
887
+ chatContainer.addEventListener('scroll', () => {
888
+ if (chatContainer.scrollTop === 0) {
889
+ loadMoreHistory();
890
+ }
891
+ });
892
+ ```
893
+
894
+ Alternatively, to fetch all history at once in a loop:
895
+
896
+ ```ts
897
+ let token: string | undefined = history?.nextPageToken ?? undefined;
898
+ let allMessages = [...(history?.chatMessages ?? [])];
899
+
900
+ while (token) {
901
+ const response = await chatSDK.getPersistentChatHistory({
902
+ pageSize: 25,
903
+ pageToken: token
904
+ });
905
+
906
+ if (response && response.chatMessages.length > 0) {
907
+ allMessages = [...allMessages, ...response.chatMessages];
908
+ token = response.nextPageToken ?? undefined;
909
+ } else {
910
+ break;
911
+ }
912
+ }
913
+
914
+ console.log(`Total messages retrieved: ${allMessages.length}`);
915
+ ```
916
+
917
+ #### Response Shape
918
+
919
+ The response type is exported from the SDK and can be imported for TypeScript usage:
920
+
921
+ ```ts
922
+ import { GetPersistentChatHistoryResponse } from '@microsoft/omnichannel-chat-sdk';
923
+ ```
924
+
925
+ ```ts
926
+ type GetPersistentChatHistoryResponse = {
927
+ chatMessages: PersistentChatHistoryMessage[];
928
+ nextPageToken: string | null; // null when no more pages
929
+ }
930
+
931
+ type PersistentChatHistoryMessage = {
932
+ content: string; // Message text
933
+ contentType: number; // Content type identifier
934
+ createdDateTime: string; // ISO 8601 timestamp
935
+ from: {
936
+ application: { // Sender application info
937
+ displayName: string; // e.g., agent name or bot name
938
+ id: string;
939
+ } | null;
940
+ };
941
+ id: string; // Unique message identifier
942
+ attachments: unknown[]; // File attachments if any
943
+ additionalData: {
944
+ deliveryMode: string; // Delivery channel
945
+ ConversationId: string; // Conversation the message belongs to
946
+ tags: string; // Message tags
947
+ };
948
+ }
949
+ ```
950
+
951
+ #### Error Handling
952
+
953
+ ```ts
954
+ try {
955
+ const history = await chatSDK.getPersistentChatHistory({ pageSize: 25 });
956
+ // Process messages...
957
+ } catch (error) {
958
+ if (error.message === 'ChatSDKNotInitialized') {
959
+ // SDK not initialized — call chatSDK.initialize() first
960
+ }
961
+ if (error.message === 'PersistentChatNotEnabled') {
962
+ // Persistent chat is not enabled for this widget
963
+ }
964
+ if (error.message === 'AuthenticatedUserTokenNotFound') {
965
+ // User is not authenticated — configure getAuthToken
966
+ }
967
+ if (error.message === 'PersistentChatConversationRetrievalFailure') {
968
+ // Server error fetching history — retry or handle gracefully
969
+ }
970
+ }
971
+ ```
972
+
738
973
  ### Chat Reconnect with Authenticated User
739
974
 
740
975
  > See <https://docs.microsoft.com/en-us/dynamics365/customer-service/configure-reconnect-chat?tabs=customerserviceadmincenter#enable-reconnection-to-a-previous-chat-session> on how to set up chat reconnect
@@ -30,7 +30,9 @@ import InitializeOptionalParams from "./core/InitializeOptionalParams";
30
30
  import LiveWorkItemDetails from "./core/LiveWorkItemDetails";
31
31
  import OmnichannelConfig from "./core/OmnichannelConfig";
32
32
  import OmnichannelMessage from "./core/messaging/OmnichannelMessage";
33
+ import OmnichannelStreamingMessage from "./core/messaging/OmnichannelStreamingMessage";
33
34
  import OnNewMessageOptionalParams from "./core/messaging/OnNewMessageOptionalParams";
35
+ import OnStreamingMessageOptionalParams from "./core/messaging/OnStreamingMessageOptionalParams";
34
36
  import PostChatContext from "./core/PostChatContext";
35
37
  import StartChatOptionalParams from "./core/StartChatOptionalParams";
36
38
  declare class OmnichannelChatSDK {
@@ -50,6 +52,7 @@ declare class OmnichannelChatSDK {
50
52
  sessionId: string | null;
51
53
  private chatOperationInProgress;
52
54
  private pendingOperations;
55
+ private deferInitialAuth;
53
56
  private unqServicesOrgUrl;
54
57
  private coreServicesOrgUrl;
55
58
  private dynamicsLocationCode;
@@ -170,7 +173,36 @@ declare class OmnichannelChatSDK {
170
173
  sendMessage(message: ChatSDKMessage): Promise<OmnichannelMessage | void>;
171
174
  onNewMessage(onNewMessageCallback: CallableFunction, optionalParams?: OnNewMessageOptionalParams): Promise<void>;
172
175
  sendTypingEvent(): Promise<void>;
176
+ /**
177
+ * Fetches unread message count for the authenticated user.
178
+ * Auth-only — does not require an active chat session.
179
+ */
180
+ getUnreadMessageCount(): Promise<object>;
181
+ /**
182
+ * Sends a read receipt for a specific message.
183
+ * Authenticated: calls MRT (updates NRD + forwards to ACS).
184
+ * Unauthenticated: calls ACS directly.
185
+ */
186
+ sendReadReceipt(messageId: string): Promise<void>;
173
187
  onTypingEvent(onTypingEventCallback: CallableFunction): Promise<void>;
188
+ /**
189
+ * Subscribes to ACS-driven streaming message chunks for progressive bot message rendering.
190
+ * Each chunk contains the full assembled text so far (not just the delta).
191
+ * Existing onNewMessage consumers continue receiving final messages without changes.
192
+ *
193
+ * Available only in LiveChatVersion.V2. Must call startChat() before registering.
194
+ *
195
+ * @param onStreamingMessageCallback - Called for each streaming chunk
196
+ * @param optionalParams - Reserved for future configuration
197
+ * @example
198
+ * chatSDK.onStreamingMessage((message) => {
199
+ * switch (message.streamingMetadata.streamingMessageType) {
200
+ * case "streaming": // Update bubble with message.content
201
+ * case "final": // Stream complete
202
+ * }
203
+ * });
204
+ */
205
+ onStreamingMessage(onStreamingMessageCallback: (message: OmnichannelStreamingMessage) => void, optionalParams?: OnStreamingMessageOptionalParams): Promise<void>;
174
206
  onAgentEndSession(onAgentEndSessionCallback: (message: IRawThread | ParticipantsRemovedEvent) => void): Promise<void>;
175
207
  uploadFileAttachment(fileInfo: IFileInfo | File): Promise<UploadFileAttachmentResponse>;
176
208
  downloadFileAttachment(fileMetadata: FileMetadata | IFileMetadata): Promise<Blob>;
@@ -181,6 +213,9 @@ declare class OmnichannelChatSDK {
181
213
  getVoiceVideoCalling(voiceVideoCallingOptionalParams?: VoiceVideoCallingOptionalParams): Promise<GetVoiceVideoCallingResponse>;
182
214
  getPostChatSurveyContext(): Promise<PostChatContext>;
183
215
  getAgentAvailability(optionalParams?: GetAgentAvailabilityOptionalParams): Promise<GetAgentAvailabilityResponse>;
216
+ authenticateChat(tokenOrProvider: string | (() => Promise<string>), optionalParams?: {
217
+ refreshChatToken?: boolean;
218
+ }): Promise<void>;
184
219
  startPolling(): Promise<void>;
185
220
  stopPolling(): Promise<void>;
186
221
  private populateInitChatOptionalParam;
@@ -194,6 +229,13 @@ declare class OmnichannelChatSDK {
194
229
  private setCallingOptionConfiguration;
195
230
  private setLiveChatVersionConfiguration;
196
231
  private setWidgetSnippetBaseUrl;
232
+ /**
233
+ * Creates diagnostic data for getChatConfig errors using the error classifier
234
+ * @param e The error object
235
+ * @param clientElapsedMs Optional elapsed time in milliseconds from client's perspective
236
+ * @returns Diagnostic data with clientElapsedMs, online status, and cancellation reason
237
+ */
238
+ private createGetChatConfigDiagnosticData;
197
239
  private getChatConfig;
198
240
  private buildConfigurations;
199
241
  private resolveIC3ClientUrl;