@microsoft/omnichannel-chat-sdk 2.0.0 → 2.0.1-main.07cfdec

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/README.md CHANGED
@@ -22,7 +22,6 @@ Please make sure you have a chat widget configured before using this package or
22
22
  - [SDK Methods](#sdk-methods)
23
23
  - [Initialization](#initialization)
24
24
  - [Start Chat](#start-chat)
25
- - [Authenticate Chat](#authenticate-chat)
26
25
  - [End Chat](#end-chat)
27
26
  - [Get Pre-Chat Survey](#get-pre-chat-survey)
28
27
  - [Get Live Chat Config](#get-live-chat-config)
@@ -114,9 +113,13 @@ For a detailed tracking of the releases, please refer to the [Changelog document
114
113
 
115
114
  _**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.
116
115
 
116
+ _**Known issue:**_ Versions earlier than 1.11.6 can start duplicate conversations when an application calls `startChat()` again before the previous call is complete. Upgrade to 1.11.8 or later. See [Concurrent `startChat()` calls in versions before 1.11.6](docs/KNOWN_ISSUE_CONCURRENT_STARTCHAT.md).
117
+
117
118
  | Version | Docs | Release Date | End of Support | Deprecated |
118
119
  | -- | -- | -- | -- | -- |
120
+ | 2.0.1 | [Release Notes](https://github.com/microsoft/omnichannel-chat-sdk/releases/tag/v2.0.1) | Oct 1st 2026 | Oct 1st 2027 | |
119
121
  | 2.0.0 | [Migration Guide](docs/MIGRATION_2.0.md) / [Release Notes](https://github.com/microsoft/omnichannel-chat-sdk/releases/tag/v2.0.0) | Aug 13th 2026 | Aug 13th 2027 | |
122
+ | 1.11.8 | [Release Notes](https://github.com/microsoft/omnichannel-chat-sdk/releases/tag/v1.11.8) | Feb 2nd 2026 | Feb 2nd 2027 | |
120
123
  | 1.11.4 | [Release Notes](https://github.com/microsoft/omnichannel-chat-sdk/releases/tag/v1.11.4) | Jul 17th 2025 | Jul 17th 2026 | |
121
124
  | 1.11.3 | [Release Notes](https://github.com/microsoft/omnichannel-chat-sdk/releases/tag/v1.11.3) | Jul 14th 2025 | Jul 14th 2026 | |
122
125
  | 1.11.2 | [Release Notes](https://github.com/microsoft/omnichannel-chat-sdk/releases/tag/v1.11.2) | Jun 24th 2025 | Jun 24th 2026 | |
@@ -135,7 +138,7 @@ The npm `latest` dist-tag can point to a `main` prerelease. Use the exact versio
135
138
 
136
139
  Regenerate the application lockfile after the update. Then run the application build and tests on Node.js 22.
137
140
 
138
- Version `2.0.0` adds progressive bot-message streaming, mid-conversation authentication, read receipts, and unread-message counts. Existing `onNewMessage` handlers continue to receive final streaming messages.
141
+ Version `2.0.0` adds progressive bot-message streaming, read receipts, and unread-message counts. Existing `onNewMessage` handlers continue to receive final streaming messages.
139
142
 
140
143
  See the [2.0 migration guide](docs/MIGRATION_2.0.md) for the complete upgrade and validation procedure.
141
144
 
@@ -331,35 +334,14 @@ const optionalParams = {
331
334
  await chatSDK.startChat(optionalParams);
332
335
  ```
333
336
 
334
- ### Authenticate Chat
335
-
336
- It authenticates an active unauthenticated conversation. Enable optional authenticated sign-in for the workstream before you use this method.
337
-
338
- Call `initialize()` and `startChat()` before `authenticateChat()`. The first argument can be a token or an asynchronous token provider.
339
-
340
- ```ts
341
- await chatSDK.initialize();
342
- await chatSDK.startChat();
343
-
344
- await chatSDK.authenticateChat(async () => {
345
- const response = await fetch("https://contoso.example/token");
346
- if (!response.ok) {
347
- throw new Error("Token request failed");
348
- }
349
-
350
- return response.text();
351
- }, {
352
- refreshChatToken: true
353
- });
354
- ```
355
-
356
- Set `refreshChatToken` to `true` when subsequent SDK calls must use a refreshed authenticated chat token.
337
+ ### End Chat
357
338
 
358
- The method throws `InvalidConversation` when no conversation is active. It throws `MidConversationAuthFailure` when token resolution or authentication fails.
339
+ It ends the current conversation for non-persistent workstreams.
359
340
 
360
- ### End Chat
341
+ For persistent workstreams, will end the conversation only if this feature is enabled:
361
342
 
362
- It ends the current Omnichannel conversation.
343
+ * The "Modern" UI has been created and set to active for the channel in use (See: [Configure a chat widget | Microsoft Learn](https://learn.microsoft.com/dynamics365/customer-service/administer/add-chat-widget))
344
+ * In channel setup, on the "Chat widget" tab, the option "Customer can end conversations" is set to On
363
345
 
364
346
  ```ts
365
347
  await chatSDK.endChat();
@@ -503,7 +485,7 @@ chatSDK.onNewMessage((message) => {
503
485
 
504
486
  ### On Streaming Message
505
487
 
506
- It subscribes to progressive ACS bot-message updates. This API is available only for Live Chat version 2.
488
+ It subscribes to progressive ACS bot-message updates.
507
489
 
508
490
  Enable streaming when you start the conversation. Then register the handler after `startChat()` completes.
509
491
 
@@ -531,7 +513,7 @@ await chatSDK.onStreamingMessage((message) => {
531
513
 
532
514
  `streamingMessageType` can be `start`, `informative`, `streaming`, or `final`. A final message also reaches existing `onNewMessage` handlers.
533
515
 
534
- Calling this method before `startChat()` throws `UninitializedConversation`. Calling it for another Live Chat version throws `UnsupportedLiveChatVersion`.
516
+ Calling this method before `startChat()` throws `UninitializedConversation`. If the conversation does not use ACS, this method throws `UnsupportedLiveChatVersion`.
535
517
 
536
518
  ### On Typing Event
537
519
 
@@ -690,7 +672,7 @@ const agentAvailability = await chatSDK.getAgentAvailability();
690
672
 
691
673
  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.
692
674
 
693
- Authenticated chat sends the receipt through Messaging Runtime. Unauthenticated chat sends it through ACS and requires Live Chat version 2.
675
+ Authenticated chat sends the receipt through Messaging Runtime. Unauthenticated chat sends the receipt through ACS.
694
676
 
695
677
  ```ts
696
678
  await chatSDK.sendReadReceipt(messageId: string);
@@ -109,6 +109,7 @@ var startPolling_1 = require("./commands/startPolling");
109
109
  var stopPolling_1 = require("./commands/stopPolling");
110
110
  var urlResolvers_1 = require("./utils/urlResolvers");
111
111
  var OmnichannelConfigValidator_1 = require("./validators/OmnichannelConfigValidator");
112
+ var prefetchedConfigValidator_1 = require("./validators/prefetchedConfigValidator");
112
113
  var OmnichannelChatSDK = /** @class */ (function () {
113
114
  function OmnichannelChatSDK(omnichannelConfig, chatSDKConfig) {
114
115
  if (chatSDKConfig === void 0) { chatSDKConfig = SDKConfigValidators_1.defaultChatSDKConfig; }
@@ -1281,10 +1282,10 @@ var OmnichannelChatSDK = /** @class */ (function () {
1281
1282
  };
1282
1283
  OmnichannelChatSDK.prototype.closeChat = function (endChatOptionalParams) {
1283
1284
  return __awaiter(this, void 0, void 0, function () {
1284
- var cleanupMetadata, sessionCloseOptionalParams, isReconnectChat, isChatReconnect, error_14;
1285
- var _a, _b;
1286
- return __generator(this, function (_c) {
1287
- switch (_c.label) {
1285
+ var cleanupMetadata, sessionCloseOptionalParams, sessionCloseRequestId, isReconnectChat, isChatReconnect, error_14;
1286
+ var _a, _b, _c, _d, _e, _f;
1287
+ return __generator(this, function (_g) {
1288
+ switch (_g.label) {
1288
1289
  case 0:
1289
1290
  cleanupMetadata = {
1290
1291
  RequestId: this.requestId,
@@ -1294,34 +1295,43 @@ var OmnichannelChatSDK = /** @class */ (function () {
1294
1295
  // in case a session was ended by agent or disconnected, there is no need to close the session
1295
1296
  this.scenarioMarker.startScenario(TelemetryEvent_1.default.CloseChatSession, cleanupMetadata);
1296
1297
  if (!!(endChatOptionalParams === null || endChatOptionalParams === void 0 ? void 0 : endChatOptionalParams.isSessionEnded)) return [3 /*break*/, 5];
1297
- _c.label = 1;
1298
+ _g.label = 1;
1298
1299
  case 1:
1299
- _c.trys.push([1, 3, , 4]);
1300
+ _g.trys.push([1, 3, , 4]);
1300
1301
  sessionCloseOptionalParams = {};
1302
+ sessionCloseRequestId = this.requestId;
1301
1303
  if (this.isPersistentChat && !((_a = this.chatSDKConfig.persistentChat) === null || _a === void 0 ? void 0 : _a.disable)) {
1302
1304
  isReconnectChat = this.reconnectId !== null ? true : false;
1303
1305
  sessionCloseOptionalParams.isPersistentChat = this.isPersistentChat;
1304
1306
  sessionCloseOptionalParams.isReconnectChat = isReconnectChat;
1307
+ if ((0, parsers_1.parseLowerCaseString)((_c = (_b = this.liveChatConfig) === null || _b === void 0 ? void 0 : _b.LiveWSAndLiveChatEngJoin) === null || _c === void 0 ? void 0 : _c.msdyn_enablecustomerclosepersistentchat) === "true" &&
1308
+ isReconnectChat &&
1309
+ typeof this.reconnectId === "string" &&
1310
+ this.reconnectId.length > 0 &&
1311
+ (0, parsers_1.parseLowerCaseString)((_e = (_d = this.liveChatConfig) === null || _d === void 0 ? void 0 : _d.LcwFcbConfiguration) === null || _e === void 0 ? void 0 : _e.lcwPersistentChatCustomerEndEnabled) === "true") {
1312
+ sessionCloseRequestId = this.reconnectId;
1313
+ }
1305
1314
  }
1306
- if (this.isChatReconnect && !((_b = this.chatSDKConfig.chatReconnect) === null || _b === void 0 ? void 0 : _b.disable) && !this.isPersistentChat) {
1315
+ if (this.isChatReconnect && !((_f = this.chatSDKConfig.chatReconnect) === null || _f === void 0 ? void 0 : _f.disable) && !this.isPersistentChat) {
1307
1316
  isChatReconnect = this.reconnectId !== null ? true : false;
1308
1317
  this.requestId = isChatReconnect ? this.reconnectId : this.requestId; // Chat Reconnect session to close
1318
+ sessionCloseRequestId = this.requestId;
1309
1319
  sessionCloseOptionalParams.isReconnectChat = isChatReconnect;
1310
1320
  }
1311
1321
  if (this.authenticatedUserToken) {
1312
1322
  sessionCloseOptionalParams.authenticatedUserToken = this.authenticatedUserToken;
1313
1323
  }
1314
- return [4 /*yield*/, this.OCClient.sessionClose(this.requestId, sessionCloseOptionalParams)];
1324
+ return [4 /*yield*/, this.OCClient.sessionClose(sessionCloseRequestId, sessionCloseOptionalParams)];
1315
1325
  case 2:
1316
- _c.sent();
1326
+ _g.sent();
1317
1327
  return [3 /*break*/, 4];
1318
1328
  case 3:
1319
- error_14 = _c.sent();
1329
+ error_14 = _g.sent();
1320
1330
  exceptionThrowers_1.default.throwConversationClosureFailure(error_14, this.scenarioMarker, TelemetryEvent_1.default.CloseChatSession, __assign(__assign({}, cleanupMetadata), { isSessionEnded: String(!(endChatOptionalParams === null || endChatOptionalParams === void 0 ? void 0 : endChatOptionalParams.isSessionEnded)) }));
1321
1331
  return [3 /*break*/, 4];
1322
1332
  case 4:
1323
1333
  this.scenarioMarker.completeScenario(TelemetryEvent_1.default.CloseChatSession, cleanupMetadata);
1324
- _c.label = 5;
1334
+ _g.label = 5;
1325
1335
  case 5: return [2 /*return*/];
1326
1336
  }
1327
1337
  });
@@ -3395,53 +3405,95 @@ var OmnichannelChatSDK = /** @class */ (function () {
3395
3405
  };
3396
3406
  OmnichannelChatSDK.prototype.getChatConfig = function () {
3397
3407
  return __awaiter(this, arguments, void 0, function (optionalParams) {
3398
- var sendCacheHeaders, bypassCache, liveChatConfig, startTime, error_30, clientElapsedMs, _a;
3399
- var _b, _c;
3408
+ var sendCacheHeaders, _a, prefetchedLiveChatConfig, prefetchedConfigAttestation, bypassCache, prefetchAttempted, prefetchResult, prefetchError_1, liveChatConfig, startTime, error_30, clientElapsedMs, _b;
3409
+ var _c, _d;
3400
3410
  if (optionalParams === void 0) { optionalParams = {}; }
3401
- return __generator(this, function (_d) {
3402
- switch (_d.label) {
3411
+ return __generator(this, function (_e) {
3412
+ switch (_e.label) {
3403
3413
  case 0:
3404
3414
  sendCacheHeaders = optionalParams.sendCacheHeaders;
3415
+ _a = optionalParams, prefetchedLiveChatConfig = _a.prefetchedLiveChatConfig, prefetchedConfigAttestation = _a.prefetchedConfigAttestation;
3405
3416
  bypassCache = sendCacheHeaders === true;
3406
- startTime = typeof performance !== 'undefined' ? performance.now() : undefined;
3407
- _d.label = 1;
3417
+ prefetchAttempted = prefetchedLiveChatConfig !== undefined && prefetchedLiveChatConfig !== null;
3418
+ if (!prefetchAttempted) return [3 /*break*/, 5];
3419
+ _e.label = 1;
3408
3420
  case 1:
3409
- _d.trys.push([1, 3, , 8]);
3410
- return [4 /*yield*/, this.OCClient.getChatConfig(this.requestId, bypassCache)];
3421
+ _e.trys.push([1, 4, , 5]);
3422
+ prefetchResult = (0, prefetchedConfigValidator_1.default)(prefetchedLiveChatConfig, prefetchedConfigAttestation, { orgId: this.omnichannelConfig.orgId, widgetId: this.omnichannelConfig.widgetId }, bypassCache, this.omnichannelConfig.orgUrl);
3423
+ if (!prefetchResult.accepted) return [3 /*break*/, 3];
3424
+ // Ordered so nothing is latched from a payload we may still
3425
+ // reject: building the configuration is the step that can
3426
+ // throw, and evaluating attachment support flips a flag that
3427
+ // is never turned back off.
3428
+ return [4 /*yield*/, this.buildConfigurations(prefetchedLiveChatConfig)];
3411
3429
  case 2:
3412
- liveChatConfig = _d.sent();
3430
+ // Ordered so nothing is latched from a payload we may still
3431
+ // reject: building the configuration is the step that can
3432
+ // throw, and evaluating attachment support flips a flag that
3433
+ // is never turned back off.
3434
+ _e.sent();
3435
+ this.liveChatConfig = prefetchedLiveChatConfig;
3436
+ this.evaluateAMSAvailability();
3437
+ this.scenarioMarker.singleRecord(TelemetryEvent_1.default.PrefetchedLiveChatConfigUsed, {
3438
+ RequestId: this.requestId || ""
3439
+ });
3440
+ return [2 /*return*/, this.liveChatConfig];
3441
+ case 3:
3442
+ this.scenarioMarker.singleRecord(TelemetryEvent_1.default.PrefetchedLiveChatConfigRejected, {
3443
+ RequestId: this.requestId || "",
3444
+ ExceptionDetails: JSON.stringify({ reason: prefetchResult.reason })
3445
+ });
3446
+ return [3 /*break*/, 5];
3447
+ case 4:
3448
+ prefetchError_1 = _e.sent();
3449
+ // Adoption itself failed (e.g. buildConfigurations rejected the
3450
+ // payload). Fall through rather than surface it: the network fetch
3451
+ // below is the correct, working behavior.
3452
+ this.scenarioMarker.singleRecord(TelemetryEvent_1.default.PrefetchedLiveChatConfigRejected, {
3453
+ RequestId: this.requestId || "",
3454
+ ExceptionDetails: JSON.stringify({ reason: "Exception", error: "".concat(prefetchError_1) })
3455
+ });
3456
+ return [3 /*break*/, 5];
3457
+ case 5:
3458
+ startTime = typeof performance !== 'undefined' ? performance.now() : undefined;
3459
+ _e.label = 6;
3460
+ case 6:
3461
+ _e.trys.push([6, 8, , 13]);
3462
+ return [4 /*yield*/, this.OCClient.getChatConfig(this.requestId, bypassCache)];
3463
+ case 7:
3464
+ liveChatConfig = _e.sent();
3413
3465
  this.liveChatConfig = liveChatConfig;
3414
3466
  this.evaluateAMSAvailability();
3415
3467
  this.buildConfigurations(liveChatConfig);
3416
3468
  /* istanbul ignore next */
3417
3469
  this.debug && console.log("[OmnichannelChatSDK][getChatConfig][liveChatVersion] ".concat(this.liveChatVersion));
3418
3470
  return [2 /*return*/, this.liveChatConfig];
3419
- case 3:
3420
- error_30 = _d.sent();
3471
+ case 8:
3472
+ error_30 = _e.sent();
3421
3473
  clientElapsedMs = startTime !== undefined
3422
3474
  ? Math.round(performance.now() - startTime)
3423
3475
  : undefined;
3424
3476
  // Attach timing info to error object for outer catch blocks to use
3425
3477
  // eslint-disable-next-line @typescript-eslint/no-explicit-any
3426
3478
  error_30.__chatConfigElapsedMs = clientElapsedMs;
3427
- if (!(0, internalUtils_1.isCoreServicesOrgUrlDNSError)(error_30, this.coreServicesOrgUrl, this.dynamicsLocationCode)) return [3 /*break*/, 6];
3479
+ if (!(0, internalUtils_1.isCoreServicesOrgUrlDNSError)(error_30, this.coreServicesOrgUrl, this.dynamicsLocationCode)) return [3 /*break*/, 11];
3428
3480
  this.omnichannelConfig.orgUrl = this.unqServicesOrgUrl;
3429
- _a = this;
3481
+ _b = this;
3430
3482
  return [4 /*yield*/, ocsdk_1.SDKProvider.getSDK(this.omnichannelConfig, (0, createOcSDKConfiguration_1.default)(false), this.ocSdkLogger)];
3431
- case 4:
3432
- _a.OCClient = _d.sent();
3483
+ case 9:
3484
+ _b.OCClient = _e.sent();
3433
3485
  return [4 /*yield*/, this.OCClient.getChatConfig(this.requestId, bypassCache)];
3434
- case 5:
3435
- liveChatConfig = _d.sent(); // Bubble up error by default to throw ChatConfigRetrievalFailure
3436
- return [3 /*break*/, 7];
3437
- case 6:
3486
+ case 10:
3487
+ liveChatConfig = _e.sent(); // Bubble up error by default to throw ChatConfigRetrievalFailure
3488
+ return [3 /*break*/, 12];
3489
+ case 11:
3438
3490
  // eslint-disable-next-line @typescript-eslint/no-explicit-any
3439
- if (((_c = (_b = error_30.response) === null || _b === void 0 ? void 0 : _b.headers) === null || _c === void 0 ? void 0 : _c.errorcode) && parseInt(error_30.response.headers.errorcode) === OmnichannelErrorCodes_1.default.WidgetNotFound) {
3491
+ if (((_d = (_c = error_30.response) === null || _c === void 0 ? void 0 : _c.headers) === null || _d === void 0 ? void 0 : _d.errorcode) && parseInt(error_30.response.headers.errorcode) === OmnichannelErrorCodes_1.default.WidgetNotFound) {
3440
3492
  console.warn("No widget with the given app id is present in the system.");
3441
3493
  }
3442
3494
  throw error_30; // Bubble up error by default to throw ChatConfigRetrievalFailure
3443
- case 7: return [3 /*break*/, 8];
3444
- case 8: return [2 /*return*/, this.liveChatConfig];
3495
+ case 12: return [3 /*break*/, 13];
3496
+ case 13: return [2 /*return*/, this.liveChatConfig];
3445
3497
  }
3446
3498
  });
3447
3499
  });
@@ -3451,18 +3503,23 @@ var OmnichannelChatSDK = /** @class */ (function () {
3451
3503
  return __awaiter(this, void 0, void 0, function () {
3452
3504
  var dataMaskingConfig, authSettings, liveWSAndLiveChatEngJoin, liveChatVersion, chatWidgetLanguage;
3453
3505
  return __generator(this, function (_a) {
3454
- dataMaskingConfig = liveChatConfig.DataMaskingInfo, authSettings = liveChatConfig.LiveChatConfigAuthSettings, liveWSAndLiveChatEngJoin = liveChatConfig.LiveWSAndLiveChatEngJoin, liveChatVersion = liveChatConfig.LiveChatVersion, chatWidgetLanguage = liveChatConfig.ChatWidgetLanguage;
3455
- Promise.all([
3456
- this.setDataMaskingConfiguration(dataMaskingConfig),
3457
- this.setPrechatConfigurations(liveWSAndLiveChatEngJoin),
3458
- this.setAuthSettingConfig(authSettings),
3459
- this.setPersistentChatConfiguration(liveWSAndLiveChatEngJoin),
3460
- this.setCallingOptionConfiguration(liveWSAndLiveChatEngJoin),
3461
- this.setLocaleIdConfiguration(chatWidgetLanguage),
3462
- this.setLiveChatVersionConfiguration(liveChatVersion),
3463
- this.setWidgetSnippetBaseUrl(liveWSAndLiveChatEngJoin)
3464
- ]);
3465
- return [2 /*return*/];
3506
+ switch (_a.label) {
3507
+ case 0:
3508
+ dataMaskingConfig = liveChatConfig.DataMaskingInfo, authSettings = liveChatConfig.LiveChatConfigAuthSettings, liveWSAndLiveChatEngJoin = liveChatConfig.LiveWSAndLiveChatEngJoin, liveChatVersion = liveChatConfig.LiveChatVersion, chatWidgetLanguage = liveChatConfig.ChatWidgetLanguage;
3509
+ return [4 /*yield*/, Promise.all([
3510
+ this.setDataMaskingConfiguration(dataMaskingConfig),
3511
+ this.setPrechatConfigurations(liveWSAndLiveChatEngJoin),
3512
+ this.setAuthSettingConfig(authSettings),
3513
+ this.setPersistentChatConfiguration(liveWSAndLiveChatEngJoin),
3514
+ this.setCallingOptionConfiguration(liveWSAndLiveChatEngJoin),
3515
+ this.setLocaleIdConfiguration(chatWidgetLanguage),
3516
+ this.setLiveChatVersionConfiguration(liveChatVersion),
3517
+ this.setWidgetSnippetBaseUrl(liveWSAndLiveChatEngJoin)
3518
+ ])];
3519
+ case 1:
3520
+ _a.sent();
3521
+ return [2 /*return*/];
3522
+ }
3466
3523
  });
3467
3524
  });
3468
3525
  };