@microsoft/omnichannel-chat-sdk 2.0.0-main.b82e941 → 2.0.0-main.be72877

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
@@ -2,7 +2,7 @@
2
2
 
3
3
  [![npm version](https://badge.fury.io/js/%40microsoft%2Fomnichannel-chat-sdk.svg)](https://badge.fury.io/js/%40microsoft%2Fomnichannel-chat-sdk)
4
4
  [![install size](https://packagephobia.com/badge?p=@microsoft/omnichannel-chat-sdk)](https://packagephobia.com/result?p=@microsoft/omnichannel-chat-sdk)
5
- ![Release CI](https://github.com/microsoft/omnichannel-chat-sdk/workflows/Release%20CI/badge.svg)
5
+ [![npm Release](https://github.com/microsoft/omnichannel-chat-sdk/actions/workflows/npm-release.yml/badge.svg)](https://github.com/microsoft/omnichannel-chat-sdk/actions/workflows/npm-release.yml)
6
6
  ![npm](https://img.shields.io/npm/dm/@microsoft/omnichannel-chat-sdk)
7
7
 
8
8
  > [!IMPORTANT]
@@ -34,6 +34,7 @@ Please make sure you have a chat widget configured before using this package or
34
34
  - [Get Messages](#get-messages)
35
35
  - [Send Messages](#send-messages)
36
36
  - [On New Message](#on-new-message)
37
+ - [On Streaming Message](#on-streaming-message)
37
38
  - [On Typing Event](#on-typing-event)
38
39
  - [On Agent End Session](#on-agent-end-session)
39
40
  - [Send Typing Event](#send-typing-event)
@@ -112,18 +113,35 @@ For a detailed tracking of the releases, please refer to the [Changelog document
112
113
 
113
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.
114
115
 
115
-
116
116
  | Version | Docs | Release Date | End of Support | Deprecated |
117
117
  | -- | -- | -- | -- | -- |
118
+ | 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 | |
118
119
  | 1.11.4 | [Release Notes](https://github.com/microsoft/omnichannel-chat-sdk/releases/tag/v1.11.4) | Jul 17th 2025 | Jul 17th 2026 | |
119
120
  | 1.11.3 | [Release Notes](https://github.com/microsoft/omnichannel-chat-sdk/releases/tag/v1.11.3) | Jul 14th 2025 | Jul 14th 2026 | |
120
121
  | 1.11.2 | [Release Notes](https://github.com/microsoft/omnichannel-chat-sdk/releases/tag/v1.11.2) | Jun 24th 2025 | Jun 24th 2026 | |
121
122
  | 1.11.1 | [Release Notes](https://github.com/microsoft/omnichannel-chat-sdk/releases/tag/v1.11.1) | Jun 5th 2025 | Jun 5th 2026 | |
122
123
  | 1.11.0 | [Release Notes](https://github.com/microsoft/omnichannel-chat-sdk/releases/tag/v1.11.0) | May 27th 2025 | May 27th 2026 | |
123
124
 
125
+ ### Upgrade to 2.0.0
126
+
127
+ Version `2.0.0` requires Node.js `>=22.12.0`. This requirement also applies to the official OC SDK and AMS client dependencies.
128
+
129
+ ```bash
130
+ npm install @microsoft/omnichannel-chat-sdk@2.0.0 --save-exact
131
+ ```
132
+
133
+ The npm `latest` dist-tag can point to a `main` prerelease. Use the exact version for production.
134
+
135
+ Regenerate the application lockfile after the update. Then run the application build and tests on Node.js 22.
136
+
137
+ Version `2.0.0` adds progressive bot-message streaming, read receipts, and unread-message counts. Existing `onNewMessage` handlers continue to receive final streaming messages.
138
+
139
+ See the [2.0 migration guide](docs/MIGRATION_2.0.md) for the complete upgrade and validation procedure.
124
140
 
125
141
  ## Installation
126
142
 
143
+ Node.js `>=22.12.0` is required.
144
+
127
145
  ```console
128
146
  npm install @microsoft/omnichannel-chat-sdk --save
129
147
  ```
@@ -456,6 +474,38 @@ chatSDK.onNewMessage((message) => {
456
474
  }, optionalParams);
457
475
  ```
458
476
 
477
+ ### On Streaming Message
478
+
479
+ It subscribes to progressive ACS bot-message updates.
480
+
481
+ Enable streaming when you start the conversation. Then register the handler after `startChat()` completes.
482
+
483
+ ```ts
484
+ await chatSDK.initialize();
485
+ await chatSDK.startChat({
486
+ supportsLcwStreaming: true
487
+ });
488
+
489
+ await chatSDK.onStreamingMessage((message) => {
490
+ const { streamingMessageType, streamEndReason } = message.streamingMetadata;
491
+
492
+ // Each event contains the full assembled content, not only the new text.
493
+ renderStreamingMessage(message.id, message.content);
494
+
495
+ if (message.policyViolation) {
496
+ handlePolicyViolation(message.policyViolation.result);
497
+ }
498
+
499
+ if (streamingMessageType === "final") {
500
+ completeStreamingMessage(message.id, streamEndReason);
501
+ }
502
+ });
503
+ ```
504
+
505
+ `streamingMessageType` can be `start`, `informative`, `streaming`, or `final`. A final message also reaches existing `onNewMessage` handlers.
506
+
507
+ Calling this method before `startChat()` throws `UninitializedConversation`. If the conversation does not use ACS, this method throws `UnsupportedLiveChatVersion`.
508
+
459
509
  ### On Typing Event
460
510
 
461
511
  It subscribes to an agent typing event.
@@ -613,13 +663,15 @@ const agentAvailability = await chatSDK.getAgentAvailability();
613
663
 
614
664
  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
665
 
666
+ Authenticated chat sends the receipt through Messaging Runtime. Unauthenticated chat sends the receipt through ACS.
667
+
616
668
  ```ts
617
669
  await chatSDK.sendReadReceipt(messageId: string);
618
670
  ```
619
671
 
620
672
  ### Get Unread Message Count
621
673
 
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.
674
+ Returns unread-message data for an authenticated user. An active chat session is not required. This call is **authenticated-only** — the user must be authenticated, otherwise an `UndefinedAuthToken` error is thrown.
623
675
 
624
676
  ```ts
625
677
  const response = await chatSDK.getUnreadMessageCount();
@@ -1323,11 +1375,11 @@ const chatSDK = new OmnichannelChatSDK.OmnichannelChatSDK(omnichannelConfig, cha
1323
1375
  await chatSDK.initialize();
1324
1376
  ```
1325
1377
 
1326
- # Releasing
1378
+ ## Releasing
1327
1379
 
1328
- See [docs/RELEASING.md](docs/RELEASING.md) for how to publish new versions to npm.
1380
+ See [docs/RELEASING.md](docs/RELEASING.md) for development builds, official npm and GitHub releases, release notes, and hotfixes.
1329
1381
 
1330
- # Contributing
1382
+ ## Contributing
1331
1383
 
1332
1384
  This project welcomes contributions and suggestions. Most contributions require you to agree to a
1333
1385
  Contributor License Agreement (CLA) declaring that you have the right to, and actually do, grant us
@@ -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
  };