@microsoft/omnichannel-chat-sdk 2.0.2-main.c0f210d → 2.1.0-main.8f375cf

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.
@@ -67,6 +67,7 @@ var locale_1 = require("./utils/locale");
67
67
  var exceptionThrowers_1 = require("./utils/exceptionThrowers");
68
68
  var errorClassifier_1 = require("./utils/errorClassifier");
69
69
  var utilities_1 = require("./utils/utilities");
70
+ var messageUpdates_1 = require("./utils/messageUpdates");
70
71
  var WebUtils_1 = require("./utils/WebUtils");
71
72
  var AMSClientUtils_1 = require("./utils/AMSClientUtils");
72
73
  var SDKConfigValidators_1 = require("./validators/SDKConfigValidators");
@@ -86,6 +87,7 @@ var MessageContentType_1 = require("@microsoft/omnichannel-ic3core/lib/model/Mes
86
87
  var MessageSource_1 = require("./telemetry/MessageSource");
87
88
  var MessageType_1 = require("@microsoft/omnichannel-ic3core/lib/model/MessageType");
88
89
  var OmnichannelErrorCodes_1 = require("./core/OmnichannelErrorCodes");
90
+ var OmnichannelMessage_1 = require("./core/messaging/OmnichannelMessage");
89
91
  var PersonType_1 = require("@microsoft/omnichannel-ic3core/lib/model/PersonType");
90
92
  var ProtocoleType_1 = require("@microsoft/omnichannel-ic3core/lib/interfaces/ProtocoleType");
91
93
  var ScenarioMarker_1 = require("./telemetry/ScenarioMarker");
@@ -103,6 +105,7 @@ var location_1 = require("./utils/location");
103
105
  var internalUtils_1 = require("./utils/internalUtils");
104
106
  var loggerUtils_1 = require("./utils/loggerUtils");
105
107
  var parsers_1 = require("./utils/parsers");
108
+ var chatTokenUnauthorizedRecovery_1 = require("./utils/chatTokenUnauthorizedRecovery");
106
109
  var chatTokenRenewal_1 = require("./utils/chatTokenRenewal");
107
110
  var platform_1 = require("./utils/platform");
108
111
  var retrieveCollectorUri_1 = require("./telemetry/retrieveCollectorUri");
@@ -126,6 +129,8 @@ var OmnichannelChatSDK = /** @class */ (function () {
126
129
  this.unqServicesOrgUrl = null;
127
130
  this.coreServicesOrgUrl = null;
128
131
  this.dynamicsLocationCode = null;
132
+ this.chatTokenUnauthorizedRecovery = null;
133
+ this.chatTokenRenewedListeners = new Set();
129
134
  this.widgetSnippetBaseUrl = '';
130
135
  this.dataMaskingRules = { rules: [] };
131
136
  this.authSettings = null;
@@ -142,6 +147,8 @@ var OmnichannelChatSDK = /** @class */ (function () {
142
147
  this.isPersistentChat = false;
143
148
  this.isChatReconnect = false;
144
149
  this.reconnectId = null;
150
+ // Session key of the most recently ended chat. MRT validates it on transcript calls made after endChat.
151
+ this.endedChatSessionKey = null;
145
152
  this.refreshTokenTimer = null;
146
153
  this.AMSClientLoadCurrentState = AMSClientLoadStates_1.AMSClientLoadStates.NOT_LOADED;
147
154
  this.isMaskingDisabled = false;
@@ -877,6 +884,7 @@ var OmnichannelChatSDK = /** @class */ (function () {
877
884
  switch (_u.label) {
878
885
  case 0:
879
886
  this.isEndingChat = false;
887
+ this.endedChatSessionKey = null;
880
888
  this.scenarioMarker.startScenario(TelemetryEvent_1.default.StartChat, {
881
889
  RequestId: this.requestId
882
890
  });
@@ -958,7 +966,7 @@ var OmnichannelChatSDK = /** @class */ (function () {
958
966
  hasAuthToken: String(!!this.authenticatedUserToken)
959
967
  })
960
968
  });
961
- if (!this.authSettings) return [3 /*break*/, 15];
969
+ if (!this.authSettings) return [3 /*break*/, 16];
962
970
  if (!(isMidAuthEnabled && (deferInitialAuth || !this.authenticatedUserToken))) return [3 /*break*/, 9];
963
971
  this.scenarioMarker.singleRecord(TelemetryEvent_1.default.StartChat, {
964
972
  RequestId: this.requestId || "",
@@ -969,7 +977,7 @@ var OmnichannelChatSDK = /** @class */ (function () {
969
977
  hasAuthToken: String(!!this.authenticatedUserToken)
970
978
  })
971
979
  });
972
- return [3 /*break*/, 15];
980
+ return [3 /*break*/, 16];
973
981
  case 9:
974
982
  if (!!this.authenticatedUserToken) return [3 /*break*/, 11];
975
983
  return [4 /*yield*/, this.setAuthTokenProvider(this.chatSDKConfig.getAuthToken, { throwError: true })];
@@ -977,7 +985,7 @@ var OmnichannelChatSDK = /** @class */ (function () {
977
985
  _u.sent();
978
986
  _u.label = 11;
979
987
  case 11:
980
- if (!(optionalParams.liveChatContext && Object.keys(optionalParams.liveChatContext).length > 0)) return [3 /*break*/, 15];
988
+ if (!(optionalParams.liveChatContext && Object.keys(optionalParams.liveChatContext).length > 0)) return [3 /*break*/, 16];
981
989
  this.chatToken = optionalParams.liveChatContext.chatToken || {};
982
990
  this.requestId = optionalParams.liveChatContext.requestId || (0, ocsdk_1.uuidv4)();
983
991
  _u.label = 12;
@@ -999,12 +1007,21 @@ var OmnichannelChatSDK = /** @class */ (function () {
999
1007
  exceptionThrowers_1.default.throwAuthenticatedChatConversationRetrievalFailure(e_7, this.scenarioMarker, TelemetryEvent_1.default.StartChat, telemetryData);
1000
1008
  return [3 /*break*/, 15];
1001
1009
  case 15:
1002
- if (!(((_k = this.chatSDKConfig.useCreateConversation) === null || _k === void 0 ? void 0 : _k.disable) && this.chatToken && Object.keys(this.chatToken).length === 0)) return [3 /*break*/, 17];
1003
- return [4 /*yield*/, this.getChatToken(false)];
1010
+ // A persistent chat restore has a reconnectId, so the restore above skipped the key. Without it,
1011
+ // calls the service validates against the chat's session key (transcripts) return 401. Apply it
1012
+ // only after the chat is confirmed to belong to the signed-in user.
1013
+ this.sessionId = optionalParams.liveChatContext.sessionId || null;
1014
+ if (this.sessionId) {
1015
+ this.OCClient.sessionId = this.sessionId;
1016
+ }
1017
+ _u.label = 16;
1004
1018
  case 16:
1005
- _u.sent();
1006
- _u.label = 17;
1019
+ if (!(((_k = this.chatSDKConfig.useCreateConversation) === null || _k === void 0 ? void 0 : _k.disable) && this.chatToken && Object.keys(this.chatToken).length === 0)) return [3 /*break*/, 18];
1020
+ return [4 /*yield*/, this.getChatToken(false)];
1007
1021
  case 17:
1022
+ _u.sent();
1023
+ _u.label = 18;
1024
+ case 18:
1008
1025
  if ((_l = this.chatToken) === null || _l === void 0 ? void 0 : _l.chatId) {
1009
1026
  loggerUtils_1.default.setChatId(this.chatToken.chatId || '', this.ocSdkLogger, this.acsClientLogger, this.acsAdapterLogger, this.callingSdkLogger, this.amsClientLogger, this.ic3ClientLogger);
1010
1027
  }
@@ -1025,14 +1042,14 @@ var OmnichannelChatSDK = /** @class */ (function () {
1025
1042
  else if (this.isChatReconnect && !((_o = this.chatSDKConfig.chatReconnect) === null || _o === void 0 ? void 0 : _o.disable) && !this.isPersistentChat) {
1026
1043
  sessionInitOptionalParams.reconnectId = this.reconnectId;
1027
1044
  }
1028
- if (!((0, parsers_1.parseLowerCaseString)((_q = (_p = this.liveChatConfig) === null || _p === void 0 ? void 0 : _p.LiveWSAndLiveChatEngJoin) === null || _q === void 0 ? void 0 : _q.msdyn_requestvisitorlocation) === "true")) return [3 /*break*/, 19];
1045
+ if (!((0, parsers_1.parseLowerCaseString)((_q = (_p = this.liveChatConfig) === null || _p === void 0 ? void 0 : _p.LiveWSAndLiveChatEngJoin) === null || _q === void 0 ? void 0 : _q.msdyn_requestvisitorlocation) === "true")) return [3 /*break*/, 20];
1029
1046
  return [4 /*yield*/, (0, location_1.getLocationInfo)(this.scenarioMarker, this.chatToken.chatId, this.requestId)];
1030
- case 18:
1047
+ case 19:
1031
1048
  location_2 = _u.sent();
1032
1049
  sessionInitOptionalParams.initContext.latitude = location_2.latitude;
1033
1050
  sessionInitOptionalParams.initContext.longitude = location_2.longitude;
1034
- _u.label = 19;
1035
- case 19:
1051
+ _u.label = 20;
1052
+ case 20:
1036
1053
  sessionInitPromise = function () { return __awaiter(_this, void 0, void 0, function () {
1037
1054
  var error_6, telemetryData;
1038
1055
  var _a, _b, _c;
@@ -1098,10 +1115,10 @@ var OmnichannelChatSDK = /** @class */ (function () {
1098
1115
  });
1099
1116
  }); };
1100
1117
  messagingClientPromise = function () { return __awaiter(_this, void 0, void 0, function () {
1101
- var chatAdapterConfig, error_8, telemetryData, _a, error_9, telemetryData, error_10, telemetryData, _b, error_11, telemetryData;
1102
- var _c, _d;
1103
- return __generator(this, function (_e) {
1104
- switch (_e.label) {
1118
+ var chatAdapterConfig, tokenRefresher, error_8, telemetryData, _a, error_9, telemetryData, error_10, telemetryData, _b, error_11, telemetryData;
1119
+ var _c, _d, _e;
1120
+ return __generator(this, function (_f) {
1121
+ switch (_f.label) {
1105
1122
  case 0:
1106
1123
  if (!(this.liveChatVersion === LiveChatVersion_1.default.V2)) return [3 /*break*/, 8];
1107
1124
  chatAdapterConfig = {
@@ -1111,19 +1128,22 @@ var OmnichannelChatSDK = /** @class */ (function () {
1111
1128
  environmentUrl: this.chatToken.acsEndpoint,
1112
1129
  pollingInterval: 30000
1113
1130
  };
1114
- _e.label = 1;
1131
+ _f.label = 1;
1115
1132
  case 1:
1116
- _e.trys.push([1, 3, , 4]);
1133
+ _f.trys.push([1, 3, , 4]);
1134
+ tokenRefresher = this.createChatTokenRefresher(chatAdapterConfig.token);
1135
+ this.chatTokenUnauthorizedRecovery = this.createChatTokenUnauthorizedRecovery(chatAdapterConfig.token, tokenRefresher);
1117
1136
  return [4 /*yield*/, ((_c = this.ACSClient) === null || _c === void 0 ? void 0 : _c.initialize({
1118
1137
  token: chatAdapterConfig.token,
1119
1138
  environmentUrl: chatAdapterConfig.environmentUrl,
1120
- tokenRefresher: this.createChatTokenRefresher(chatAdapterConfig.token)
1139
+ tokenRefresher: tokenRefresher,
1140
+ unauthorizedRecovery: (_d = this.chatTokenUnauthorizedRecovery) !== null && _d !== void 0 ? _d : undefined
1121
1141
  }))];
1122
1142
  case 2:
1123
- _e.sent();
1143
+ _f.sent();
1124
1144
  return [3 /*break*/, 4];
1125
1145
  case 3:
1126
- error_8 = _e.sent();
1146
+ error_8 = _f.sent();
1127
1147
  telemetryData = {
1128
1148
  RequestId: this.requestId,
1129
1149
  ChatId: this.chatToken.chatId,
@@ -1131,22 +1151,22 @@ var OmnichannelChatSDK = /** @class */ (function () {
1131
1151
  exceptionThrowers_1.default.throwMessagingClientInitializationFailure(error_8, this.scenarioMarker, TelemetryEvent_1.default.StartChat, telemetryData);
1132
1152
  return [3 /*break*/, 4];
1133
1153
  case 4:
1134
- _e.trys.push([4, 6, , 7]);
1154
+ _f.trys.push([4, 6, , 7]);
1135
1155
  _a = this;
1136
- return [4 /*yield*/, ((_d = this.ACSClient) === null || _d === void 0 ? void 0 : _d.joinConversation({
1156
+ return [4 /*yield*/, ((_e = this.ACSClient) === null || _e === void 0 ? void 0 : _e.joinConversation({
1137
1157
  id: chatAdapterConfig.id,
1138
1158
  threadId: chatAdapterConfig.threadId,
1139
1159
  pollingInterval: chatAdapterConfig.pollingInterval
1140
1160
  }))];
1141
1161
  case 5:
1142
- _a.conversation = (_e.sent());
1162
+ _a.conversation = (_f.sent());
1143
1163
  this.scenarioMarker.completeScenario(TelemetryEvent_1.default.StartChat, {
1144
1164
  RequestId: this.requestId,
1145
1165
  ChatId: this.chatToken.chatId
1146
1166
  });
1147
1167
  return [3 /*break*/, 7];
1148
1168
  case 6:
1149
- error_9 = _e.sent();
1169
+ error_9 = _f.sent();
1150
1170
  telemetryData = {
1151
1171
  RequestId: this.requestId,
1152
1172
  ChatId: this.chatToken.chatId,
@@ -1155,17 +1175,17 @@ var OmnichannelChatSDK = /** @class */ (function () {
1155
1175
  return [3 /*break*/, 7];
1156
1176
  case 7: return [3 /*break*/, 14];
1157
1177
  case 8:
1158
- _e.trys.push([8, 10, , 11]);
1178
+ _f.trys.push([8, 10, , 11]);
1159
1179
  return [4 /*yield*/, this.IC3Client.initialize({
1160
1180
  token: this.chatToken.token,
1161
1181
  regionGtms: this.chatToken.regionGTMS,
1162
1182
  visitor: true
1163
1183
  })];
1164
1184
  case 9:
1165
- _e.sent();
1185
+ _f.sent();
1166
1186
  return [3 /*break*/, 11];
1167
1187
  case 10:
1168
- error_10 = _e.sent();
1188
+ error_10 = _f.sent();
1169
1189
  telemetryData = {
1170
1190
  RequestId: this.requestId,
1171
1191
  ChatId: this.chatToken.chatId,
@@ -1173,18 +1193,18 @@ var OmnichannelChatSDK = /** @class */ (function () {
1173
1193
  exceptionThrowers_1.default.throwMessagingClientInitializationFailure(error_10, this.scenarioMarker, TelemetryEvent_1.default.StartChat, telemetryData);
1174
1194
  return [3 /*break*/, 11];
1175
1195
  case 11:
1176
- _e.trys.push([11, 13, , 14]);
1196
+ _f.trys.push([11, 13, , 14]);
1177
1197
  _b = this;
1178
1198
  return [4 /*yield*/, this.IC3Client.joinConversation(this.chatToken.chatId)];
1179
1199
  case 12:
1180
- _b.conversation = _e.sent();
1200
+ _b.conversation = _f.sent();
1181
1201
  this.scenarioMarker.completeScenario(TelemetryEvent_1.default.StartChat, {
1182
1202
  RequestId: this.requestId,
1183
1203
  ChatId: this.chatToken.chatId
1184
1204
  });
1185
1205
  return [3 /*break*/, 14];
1186
1206
  case 13:
1187
- error_11 = _e.sent();
1207
+ error_11 = _f.sent();
1188
1208
  telemetryData = {
1189
1209
  RequestId: this.requestId,
1190
1210
  ChatId: this.chatToken.chatId,
@@ -1227,32 +1247,32 @@ var OmnichannelChatSDK = /** @class */ (function () {
1227
1247
  }
1228
1248
  });
1229
1249
  }); };
1230
- if (!!((_r = this.chatSDKConfig.useCreateConversation) === null || _r === void 0 ? void 0 : _r.disable)) return [3 /*break*/, 21];
1250
+ if (!!((_r = this.chatSDKConfig.useCreateConversation) === null || _r === void 0 ? void 0 : _r.disable)) return [3 /*break*/, 22];
1231
1251
  return [4 /*yield*/, createConversationPromise()];
1232
- case 20:
1252
+ case 21:
1233
1253
  _u.sent();
1234
- return [3 /*break*/, 23];
1235
- case 21: return [4 /*yield*/, sessionInitPromise()];
1236
- case 22:
1237
- _u.sent(); // Await the session initialization
1238
- _u.label = 23;
1254
+ return [3 /*break*/, 24];
1255
+ case 22: return [4 /*yield*/, sessionInitPromise()];
1239
1256
  case 23:
1240
- _u.trys.push([23, 25, , 27]);
1241
- return [4 /*yield*/, Promise.all([messagingClientPromise(), attachmentClientPromise()])];
1257
+ _u.sent(); // Await the session initialization
1258
+ _u.label = 24;
1242
1259
  case 24:
1243
- _u.sent();
1244
- return [3 /*break*/, 27];
1260
+ _u.trys.push([24, 26, , 28]);
1261
+ return [4 /*yield*/, Promise.all([messagingClientPromise(), attachmentClientPromise()])];
1245
1262
  case 25:
1263
+ _u.sent();
1264
+ return [3 /*break*/, 28];
1265
+ case 26:
1246
1266
  error_5 = _u.sent();
1247
1267
  // If conversation joining fails after conversation was created, clean up the conversation
1248
1268
  // Only cleanup conversations that were freshly created (not existing ones being reconnected to)
1249
1269
  return [4 /*yield*/, this.handleConversationJoinFailure(error_5, optionalParams)];
1250
- case 26:
1270
+ case 27:
1251
1271
  // If conversation joining fails after conversation was created, clean up the conversation
1252
1272
  // Only cleanup conversations that were freshly created (not existing ones being reconnected to)
1253
1273
  _u.sent();
1254
1274
  throw error_5; // Re-throw the original error
1255
- case 27:
1275
+ case 28:
1256
1276
  if (this.isPersistentChat && !((_s = this.chatSDKConfig.persistentChat) === null || _s === void 0 ? void 0 : _s.disable)) {
1257
1277
  this.refreshTokenTimer = setInterval(function () { return __awaiter(_this, void 0, void 0, function () {
1258
1278
  var error_13;
@@ -1362,7 +1382,7 @@ var OmnichannelChatSDK = /** @class */ (function () {
1362
1382
  };
1363
1383
  OmnichannelChatSDK.prototype.internalEndChat = function () {
1364
1384
  return __awaiter(this, arguments, void 0, function (endChatOptionalParams) {
1365
- var cleanupMetadata, isReactNative, isConversationalSurveyEnabled, shouldWaitForSurvey, telemetryData, surveyStarted, error_15, error_16, telemetryData;
1385
+ var cleanupMetadata, isReactNative, isConversationalSurveyEnabled, shouldWaitForSurvey, telemetryData, surveyStarted, error_15, error_16, telemetryData, endedChatId, endedSessionId;
1366
1386
  var _a, _b, _c;
1367
1387
  if (endChatOptionalParams === void 0) { endChatOptionalParams = {}; }
1368
1388
  return __generator(this, function (_d) {
@@ -1421,12 +1441,17 @@ var OmnichannelChatSDK = /** @class */ (function () {
1421
1441
  exceptionThrowers_1.default.throwConversationClosureFailure(error_16, this.scenarioMarker, TelemetryEvent_1.default.EndChat, telemetryData);
1422
1442
  return [3 /*break*/, 11];
1423
1443
  case 10:
1424
- // Cleanup always runs, regardless of success or failure
1425
- // This ensures resources are released even if closeChat or survey waiting throws
1444
+ endedChatId = this.chatToken.chatId;
1445
+ endedSessionId = this.OCClient.sessionId || this.sessionId;
1446
+ // Keep the previous chat's key when this call had no chat to end (for example a second endChat).
1447
+ if (endedChatId && endedSessionId) {
1448
+ this.endedChatSessionKey = { chatId: endedChatId, sessionId: endedSessionId };
1449
+ }
1426
1450
  (_c = this.conversation) === null || _c === void 0 ? void 0 : _c.disconnect();
1427
1451
  this.conversation = null;
1428
1452
  this.requestId = (0, ocsdk_1.uuidv4)();
1429
1453
  this.chatToken = {};
1454
+ this.chatTokenUnauthorizedRecovery = null;
1430
1455
  this.reconnectId = null;
1431
1456
  if (this.IC3Client) {
1432
1457
  this.IC3Client.dispose();
@@ -1545,6 +1570,20 @@ var OmnichannelChatSDK = /** @class */ (function () {
1545
1570
  });
1546
1571
  });
1547
1572
  };
1573
+ /**
1574
+ * Subscribes to usable chat token renewals after the current SDK context has been updated.
1575
+ * No token or other payload is passed. Read getCurrentLiveChatContext() to persist the updated context.
1576
+ * Returns an idempotent unsubscribe function. Listener failures never affect renewal.
1577
+ * Subscriptions belong to this SDK instance and survive endChat()/startChat().
1578
+ * Subscribe before startChat() to observe restoration renewals; past notifications are not replayed.
1579
+ * Unsubscribe on host teardown or before replacing a per-chat subscription.
1580
+ */
1581
+ OmnichannelChatSDK.prototype.onChatTokenRenewed = function (listener) {
1582
+ var _this = this;
1583
+ var subscription = function () { return listener(); };
1584
+ this.chatTokenRenewedListeners.add(subscription);
1585
+ return function () { _this.chatTokenRenewedListeners.delete(subscription); };
1586
+ };
1548
1587
  OmnichannelChatSDK.prototype.getCurrentLiveChatContext = function () {
1549
1588
  return __awaiter(this, void 0, void 0, function () {
1550
1589
  var chatToken, requestId, chatSession;
@@ -1843,6 +1882,7 @@ var OmnichannelChatSDK = /** @class */ (function () {
1843
1882
  var _a;
1844
1883
  _this.chatToken = __assign(__assign({}, _this.chatToken), { token: renewed.Token, expiresIn: renewed.ExpiresIn !== undefined && renewed.ExpiresIn !== null ? String(renewed.ExpiresIn) : _this.chatToken.expiresIn, voiceVideoCallToken: (_a = renewed.VoiceVideoCallToken) !== null && _a !== void 0 ? _a : _this.chatToken.voiceVideoCallToken });
1845
1884
  _this.refreshAttachmentClientToken(chatId_1);
1885
+ _this.notifyChatTokenRenewed(requestId_1, chatId_1);
1846
1886
  },
1847
1887
  onStart: function () { return _this.scenarioMarker.startScenario(TelemetryEvent_1.default.RenewChatToken, telemetryData_1); },
1848
1888
  onSuccess: function () { return _this.scenarioMarker.completeScenario(TelemetryEvent_1.default.RenewChatToken, telemetryData_1); },
@@ -1859,6 +1899,32 @@ var OmnichannelChatSDK = /** @class */ (function () {
1859
1899
  return undefined;
1860
1900
  }
1861
1901
  };
1902
+ OmnichannelChatSDK.prototype.notifyChatTokenRenewed = function (requestId, chatId) {
1903
+ var _this = this;
1904
+ var reportFailure = function (response) {
1905
+ try {
1906
+ var telemetryData = { RequestId: requestId, ChatId: chatId };
1907
+ _this.scenarioMarker.startScenario(TelemetryEvent_1.default.ChatTokenRenewedListener, telemetryData);
1908
+ _this.scenarioMarker.failScenario(TelemetryEvent_1.default.ChatTokenRenewedListener, __assign(__assign({}, telemetryData), { ExceptionDetails: JSON.stringify({ response: response }) }));
1909
+ }
1910
+ catch (_a) {
1911
+ // Subscriber telemetry must not affect renewal or become an unhandled rejection.
1912
+ }
1913
+ };
1914
+ Array.from(this.chatTokenRenewedListeners).forEach(function (listener) {
1915
+ var _a;
1916
+ if (_this.isEndingChat || _this.requestId !== requestId || ((_a = _this.chatToken) === null || _a === void 0 ? void 0 : _a.chatId) !== chatId
1917
+ || !_this.chatTokenRenewedListeners.has(listener)) {
1918
+ return;
1919
+ }
1920
+ try {
1921
+ Promise.resolve(listener()).catch(function () { return reportFailure("ListenerRejected"); });
1922
+ }
1923
+ catch (_b) {
1924
+ reportFailure("ListenerThrew");
1925
+ }
1926
+ });
1927
+ };
1862
1928
  /**
1863
1929
  * Gives the renewed chat token to the attachment client, which keeps the token it was initialized with and uses
1864
1930
  * it for every upload and download. Runs in the background and never throws: on failure, attachments keep using
@@ -1897,6 +1963,42 @@ var OmnichannelChatSDK = /** @class */ (function () {
1897
1963
  // Attachments keep using the previous token
1898
1964
  }
1899
1965
  };
1966
+ /**
1967
+ * Creates the recovery for chat requests that fail with 401 while the chat token has not
1968
+ * expired. Returns null, which keeps the existing behavior, unless chat token renewal is enabled and recovery is
1969
+ * not disabled in the SDK config.
1970
+ */
1971
+ OmnichannelChatSDK.prototype.createChatTokenUnauthorizedRecovery = function (initialToken, tokenRefresher) {
1972
+ var _this = this;
1973
+ var _a, _b, _c;
1974
+ try {
1975
+ if (!tokenRefresher
1976
+ || ((_b = (_a = this.chatSDKConfig) === null || _a === void 0 ? void 0 : _a.chatTokenRenewal) === null || _b === void 0 ? void 0 : _b.disableUnauthorizedRecovery) === true
1977
+ || !initialToken) {
1978
+ return null;
1979
+ }
1980
+ var telemetryData_3 = {
1981
+ RequestId: this.requestId,
1982
+ ChatId: (_c = this.chatToken) === null || _c === void 0 ? void 0 : _c.chatId
1983
+ };
1984
+ return (0, chatTokenUnauthorizedRecovery_1.createChatTokenUnauthorizedRecovery)({
1985
+ initialToken: initialToken,
1986
+ refreshToken: tokenRefresher,
1987
+ onStart: function () { return _this.scenarioMarker.startScenario(TelemetryEvent_1.default.ChatTokenUnauthorizedRecovery, telemetryData_3); },
1988
+ onSuccess: function (_source, usedExistingToken) {
1989
+ if (!usedExistingToken) {
1990
+ _this.scenarioMarker.completeScenario(TelemetryEvent_1.default.ChatTokenUnauthorizedRecovery, telemetryData_3);
1991
+ }
1992
+ },
1993
+ onFailure: function (source, reason) {
1994
+ _this.scenarioMarker.failScenario(TelemetryEvent_1.default.ChatTokenUnauthorizedRecovery, __assign(__assign({}, telemetryData_3), { ExceptionDetails: JSON.stringify({ response: reason, source: source }) }));
1995
+ }
1996
+ });
1997
+ }
1998
+ catch (_d) {
1999
+ return null;
2000
+ }
2001
+ };
1900
2002
  /**
1901
2003
  * Returns the token of the authenticated user to renew the chat token with, refreshed from the auth token
1902
2004
  * provider when possible because the token used to start the chat may have expired. Returns undefined for
@@ -2112,7 +2214,7 @@ var OmnichannelChatSDK = /** @class */ (function () {
2112
2214
  };
2113
2215
  OmnichannelChatSDK.prototype.onNewMessage = function (onNewMessageCallback_1) {
2114
2216
  return __awaiter(this, arguments, void 0, function (onNewMessageCallback, optionalParams) {
2115
- var postedMessages_1, messages, _i, _a, message, id, registerOnNewMessageOptionalParams;
2217
+ var postedMessages_1, customerMessageUpdates_1, getNewCustomerVersion_1, messages, _i, _a, message, id, customerMessage, customerVersion, registerOnNewMessageOptionalParams;
2116
2218
  var _this = this;
2117
2219
  var _b;
2118
2220
  if (optionalParams === void 0) { optionalParams = {}; }
@@ -2128,6 +2230,20 @@ var OmnichannelChatSDK = /** @class */ (function () {
2128
2230
  }
2129
2231
  if (!(this.liveChatVersion === LiveChatVersion_1.default.V2)) return [3 /*break*/, 3];
2130
2232
  postedMessages_1 = new Set();
2233
+ customerMessageUpdates_1 = new messageUpdates_1.MessageUpdateTracker();
2234
+ getNewCustomerVersion_1 = function (message) {
2235
+ var version = (0, messageUpdates_1.getMessageVersion)(message);
2236
+ if (version === undefined) {
2237
+ _this.scenarioMarker.singleRecord(TelemetryEvent_1.default.OnNewMessage, {
2238
+ RequestId: _this.requestId,
2239
+ ChatId: _this.chatToken.chatId,
2240
+ ExceptionDetails: "InvalidCustomerMessageVersion"
2241
+ });
2242
+ console.warn("[OmnichannelChatSDK][onNewMessage] Invalid customer message version");
2243
+ return undefined;
2244
+ }
2245
+ return customerMessageUpdates_1.shouldDeliver(message.id, version) ? version : undefined;
2246
+ };
2131
2247
  if (!(optionalParams === null || optionalParams === void 0 ? void 0 : optionalParams.rehydrate)) return [3 /*break*/, 2];
2132
2248
  this.debug && console.log('[OmnichannelChatSDK][onNewMessage] rehydrate');
2133
2249
  return [4 /*yield*/, this.getMessages()];
@@ -2139,8 +2255,16 @@ var OmnichannelChatSDK = /** @class */ (function () {
2139
2255
  if (postedMessages_1.has(id)) {
2140
2256
  continue;
2141
2257
  }
2258
+ customerMessage = (0, utilities_1.isCustomerMessage)(message);
2259
+ customerVersion = customerMessage ? (0, messageUpdates_1.getMessageVersion)(message) : undefined;
2260
+ if (customerMessage) {
2261
+ message.role = OmnichannelMessage_1.Role.User;
2262
+ }
2142
2263
  postedMessages_1.add(id);
2143
2264
  onNewMessageCallback(message);
2265
+ if (customerVersion !== undefined) {
2266
+ customerMessageUpdates_1.markDelivered(id, customerVersion);
2267
+ }
2144
2268
  }
2145
2269
  _c.label = 2;
2146
2270
  case 2:
@@ -2157,7 +2281,7 @@ var OmnichannelChatSDK = /** @class */ (function () {
2157
2281
  (_b = this.conversation) === null || _b === void 0 ? void 0 : _b.registerOnNewMessage(function (event) {
2158
2282
  var id = event.id;
2159
2283
  var isChatMessageEditedEvent = Object.keys(event).includes("editedOn");
2160
- console.log("[OmnichannelChatSDK][onNewMessage] New message received", event);
2284
+ console.log("[OmnichannelChatSDK][onNewMessage] New message received");
2161
2285
  console.log("[OmnichannelChatSDK][onNewMessage] isChatMessageEditedEvent=>", isChatMessageEditedEvent);
2162
2286
  // Guard message transformation: createOmnichannelMessage() can throw
2163
2287
  // (e.g. unexpected event shape). Without this, the throw became an
@@ -2185,9 +2309,23 @@ var OmnichannelChatSDK = /** @class */ (function () {
2185
2309
  });
2186
2310
  return;
2187
2311
  }
2312
+ var customerMessage = (0, utilities_1.isCustomerMessage)(omnichannelMessage);
2313
+ if (customerMessage && !(0, messageUpdates_1.isMessageEdited)(event)) {
2314
+ return;
2315
+ }
2316
+ var customerVersion = customerMessage ? getNewCustomerVersion_1(event) : undefined;
2317
+ if (customerMessage && customerVersion === undefined) {
2318
+ return;
2319
+ }
2320
+ if (customerMessage) {
2321
+ omnichannelMessage.role = OmnichannelMessage_1.Role.User;
2322
+ }
2188
2323
  // send callback for new messages or edited existent messages
2189
- if (!postedMessages_1.has(id) || isChatMessageEditedEvent) {
2324
+ if (customerMessage || !postedMessages_1.has(id) || isChatMessageEditedEvent) {
2190
2325
  onNewMessageCallback(omnichannelMessage);
2326
+ if (customerVersion !== undefined) {
2327
+ customerMessageUpdates_1.markDelivered(id, customerVersion);
2328
+ }
2191
2329
  console.log("[OmnichannelChatSDK][onNewMessage] Message posted");
2192
2330
  postedMessages_1.add(id);
2193
2331
  }
@@ -2769,7 +2907,8 @@ var OmnichannelChatSDK = /** @class */ (function () {
2769
2907
  };
2770
2908
  OmnichannelChatSDK.prototype.emailLiveChatTranscript = function (body_1) {
2771
2909
  return __awaiter(this, arguments, void 0, function (body, optionalParams) {
2772
- var emailTranscriptOptionalParams, requestId, chatToken, chatId, sessionId, emailRequestBody, error_27;
2910
+ var emailTranscriptOptionalParams, requestId, chatToken, chatId, requestSessionKey, emailRequestBody_1, error_27;
2911
+ var _this = this;
2773
2912
  var _a;
2774
2913
  if (optionalParams === void 0) { optionalParams = {}; }
2775
2914
  return __generator(this, function (_b) {
@@ -2779,16 +2918,12 @@ var OmnichannelChatSDK = /** @class */ (function () {
2779
2918
  requestId = this.requestId;
2780
2919
  chatToken = this.chatToken;
2781
2920
  chatId = chatToken.chatId;
2782
- sessionId = this.sessionId;
2783
2921
  if (optionalParams.liveChatContext) {
2784
2922
  requestId = optionalParams.liveChatContext.requestId;
2785
2923
  chatToken = optionalParams.liveChatContext.chatToken;
2786
2924
  chatId = chatToken.chatId;
2787
2925
  }
2788
- if ((_a = optionalParams.liveChatContext) === null || _a === void 0 ? void 0 : _a.sessionId) {
2789
- sessionId = optionalParams.liveChatContext.sessionId;
2790
- this.OCClient.sessionId = sessionId;
2791
- }
2926
+ requestSessionKey = ((_a = optionalParams.liveChatContext) === null || _a === void 0 ? void 0 : _a.sessionId) || this.getEndedChatSessionKey(chatId);
2792
2927
  this.scenarioMarker.startScenario(TelemetryEvent_1.default.EmailLiveChatTranscript, {
2793
2928
  RequestId: requestId,
2794
2929
  ChatId: chatId
@@ -2802,18 +2937,15 @@ var OmnichannelChatSDK = /** @class */ (function () {
2802
2937
  if (this.authenticatedUserToken) {
2803
2938
  emailTranscriptOptionalParams.authenticatedUserToken = this.authenticatedUserToken;
2804
2939
  }
2805
- emailRequestBody = {
2940
+ emailRequestBody_1 = {
2806
2941
  ChatId: chatId,
2807
2942
  EmailAddress: body.emailAddress,
2808
2943
  DefaultAttachmentMessage: body.attachmentMessage,
2809
2944
  CustomerLocale: body.locale || (0, locale_1.getLocaleStringFromId)(this.localeId)
2810
2945
  };
2811
- return [4 /*yield*/, this.OCClient.emailTranscript(requestId, chatToken.token, emailRequestBody, emailTranscriptOptionalParams)];
2946
+ return [4 /*yield*/, this.withRequestSessionKey(requestSessionKey, function () { return _this.OCClient.emailTranscript(requestId, chatToken.token, emailRequestBody_1, emailTranscriptOptionalParams); })];
2812
2947
  case 2:
2813
2948
  _b.sent();
2814
- if (this.sessionId) {
2815
- this.OCClient.sessionId = this.sessionId;
2816
- }
2817
2949
  this.scenarioMarker.completeScenario(TelemetryEvent_1.default.EmailLiveChatTranscript, {
2818
2950
  RequestId: requestId,
2819
2951
  ChatId: chatId
@@ -2834,7 +2966,8 @@ var OmnichannelChatSDK = /** @class */ (function () {
2834
2966
  };
2835
2967
  OmnichannelChatSDK.prototype.getLiveChatTranscript = function () {
2836
2968
  return __awaiter(this, arguments, void 0, function (optionalParams) {
2837
- var getChatTranscriptOptionalParams, requestId, chatToken, chatId, sessionId, transcriptResponse, error_28, telemetryData;
2969
+ var getChatTranscriptOptionalParams, requestId, chatToken, chatId, requestSessionKey, transcriptResponse, error_28, telemetryData;
2970
+ var _this = this;
2838
2971
  var _a, _b;
2839
2972
  if (optionalParams === void 0) { optionalParams = {}; }
2840
2973
  return __generator(this, function (_c) {
@@ -2844,7 +2977,6 @@ var OmnichannelChatSDK = /** @class */ (function () {
2844
2977
  requestId = this.requestId;
2845
2978
  chatToken = this.chatToken;
2846
2979
  chatId = chatToken.chatId;
2847
- sessionId = this.sessionId;
2848
2980
  if (optionalParams.liveChatContext) {
2849
2981
  if (this.isPersistentChat && !((_a = this.chatSDKConfig.persistentChat) === null || _a === void 0 ? void 0 : _a.disable)) {
2850
2982
  requestId = this.requestId || optionalParams.liveChatContext.requestId;
@@ -2856,10 +2988,6 @@ var OmnichannelChatSDK = /** @class */ (function () {
2856
2988
  }
2857
2989
  chatId = chatToken.chatId;
2858
2990
  }
2859
- if ((_b = optionalParams.liveChatContext) === null || _b === void 0 ? void 0 : _b.sessionId) {
2860
- sessionId = optionalParams.liveChatContext.sessionId;
2861
- this.OCClient.sessionId = sessionId;
2862
- }
2863
2991
  if (!chatId) {
2864
2992
  throw new ChatSDKError_1.ChatSDKError(ChatSDKError_1.ChatSDKErrorName.LiveChatTranscriptRetrievalFailure, undefined, {
2865
2993
  response: ChatSDKError_1.ChatSDKErrorName.LiveChatTranscriptRetrievalFailure,
@@ -2873,18 +3001,16 @@ var OmnichannelChatSDK = /** @class */ (function () {
2873
3001
  if (!this.isInitialized) {
2874
3002
  exceptionThrowers_1.default.throwUninitializedChatSDK(this.scenarioMarker, TelemetryEvent_1.default.GetLiveChatTranscript);
2875
3003
  }
3004
+ requestSessionKey = ((_b = optionalParams.liveChatContext) === null || _b === void 0 ? void 0 : _b.sessionId) || this.getEndedChatSessionKey(chatId);
2876
3005
  _c.label = 1;
2877
3006
  case 1:
2878
3007
  _c.trys.push([1, 3, , 4]);
2879
3008
  if (this.authenticatedUserToken) {
2880
3009
  getChatTranscriptOptionalParams.authenticatedUserToken = this.authenticatedUserToken;
2881
3010
  }
2882
- return [4 /*yield*/, this.OCClient.getChatTranscripts(requestId, chatToken.chatId, chatToken.token, getChatTranscriptOptionalParams)];
3011
+ return [4 /*yield*/, this.withRequestSessionKey(requestSessionKey, function () { return _this.OCClient.getChatTranscripts(requestId, chatToken.chatId, chatToken.token, getChatTranscriptOptionalParams); })];
2883
3012
  case 2:
2884
3013
  transcriptResponse = _c.sent();
2885
- if (this.sessionId) {
2886
- this.OCClient.sessionId = this.sessionId;
2887
- }
2888
3014
  this.scenarioMarker.completeScenario(TelemetryEvent_1.default.GetLiveChatTranscript, {
2889
3015
  RequestId: requestId,
2890
3016
  ChatId: chatId
@@ -2903,6 +3029,30 @@ var OmnichannelChatSDK = /** @class */ (function () {
2903
3029
  });
2904
3030
  });
2905
3031
  };
3032
+ /**
3033
+ * Returns the ended chat's session key when the call targets that chat, or null.
3034
+ */
3035
+ OmnichannelChatSDK.prototype.getEndedChatSessionKey = function (chatId) {
3036
+ var _a;
3037
+ return chatId && ((_a = this.endedChatSessionKey) === null || _a === void 0 ? void 0 : _a.chatId) === chatId ? this.endedChatSessionKey.sessionId : null;
3038
+ };
3039
+ /**
3040
+ * Sends the session key on one OCSDK request without leaving it on the shared client. OCSDK copies the
3041
+ * key into the request headers before its first await, so the previous key is restored before the HTTP wait.
3042
+ */
3043
+ OmnichannelChatSDK.prototype.withRequestSessionKey = function (sessionKey, request) {
3044
+ if (!sessionKey) {
3045
+ return request();
3046
+ }
3047
+ var previousSessionKey = this.OCClient.sessionId;
3048
+ this.OCClient.sessionId = sessionKey;
3049
+ try {
3050
+ return request();
3051
+ }
3052
+ finally {
3053
+ this.OCClient.sessionId = previousSessionKey;
3054
+ }
3055
+ };
2906
3056
  OmnichannelChatSDK.prototype.createChatAdapter = function () {
2907
3057
  return __awaiter(this, arguments, void 0, function (optionalParams) {
2908
3058
  var protocol, supportedChatAdapterProtocols, options, fileManager;