@microsoft/omnichannel-chat-sdk 2.0.1 → 2.0.2-main.355218f

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.
@@ -103,6 +103,8 @@ var location_1 = require("./utils/location");
103
103
  var internalUtils_1 = require("./utils/internalUtils");
104
104
  var loggerUtils_1 = require("./utils/loggerUtils");
105
105
  var parsers_1 = require("./utils/parsers");
106
+ var chatTokenUnauthorizedRecovery_1 = require("./utils/chatTokenUnauthorizedRecovery");
107
+ var chatTokenRenewal_1 = require("./utils/chatTokenRenewal");
106
108
  var platform_1 = require("./utils/platform");
107
109
  var retrieveCollectorUri_1 = require("./telemetry/retrieveCollectorUri");
108
110
  var startPolling_1 = require("./commands/startPolling");
@@ -125,6 +127,8 @@ var OmnichannelChatSDK = /** @class */ (function () {
125
127
  this.unqServicesOrgUrl = null;
126
128
  this.coreServicesOrgUrl = null;
127
129
  this.dynamicsLocationCode = null;
130
+ this.chatTokenUnauthorizedRecovery = null;
131
+ this.chatTokenRenewedListeners = new Set();
128
132
  this.widgetSnippetBaseUrl = '';
129
133
  this.dataMaskingRules = { rules: [] };
130
134
  this.authSettings = null;
@@ -141,6 +145,8 @@ var OmnichannelChatSDK = /** @class */ (function () {
141
145
  this.isPersistentChat = false;
142
146
  this.isChatReconnect = false;
143
147
  this.reconnectId = null;
148
+ // Session key of the most recently ended chat. MRT validates it on transcript calls made after endChat.
149
+ this.endedChatSessionKey = null;
144
150
  this.refreshTokenTimer = null;
145
151
  this.AMSClientLoadCurrentState = AMSClientLoadStates_1.AMSClientLoadStates.NOT_LOADED;
146
152
  this.isMaskingDisabled = false;
@@ -876,6 +882,7 @@ var OmnichannelChatSDK = /** @class */ (function () {
876
882
  switch (_u.label) {
877
883
  case 0:
878
884
  this.isEndingChat = false;
885
+ this.endedChatSessionKey = null;
879
886
  this.scenarioMarker.startScenario(TelemetryEvent_1.default.StartChat, {
880
887
  RequestId: this.requestId
881
888
  });
@@ -957,7 +964,7 @@ var OmnichannelChatSDK = /** @class */ (function () {
957
964
  hasAuthToken: String(!!this.authenticatedUserToken)
958
965
  })
959
966
  });
960
- if (!this.authSettings) return [3 /*break*/, 15];
967
+ if (!this.authSettings) return [3 /*break*/, 16];
961
968
  if (!(isMidAuthEnabled && (deferInitialAuth || !this.authenticatedUserToken))) return [3 /*break*/, 9];
962
969
  this.scenarioMarker.singleRecord(TelemetryEvent_1.default.StartChat, {
963
970
  RequestId: this.requestId || "",
@@ -968,7 +975,7 @@ var OmnichannelChatSDK = /** @class */ (function () {
968
975
  hasAuthToken: String(!!this.authenticatedUserToken)
969
976
  })
970
977
  });
971
- return [3 /*break*/, 15];
978
+ return [3 /*break*/, 16];
972
979
  case 9:
973
980
  if (!!this.authenticatedUserToken) return [3 /*break*/, 11];
974
981
  return [4 /*yield*/, this.setAuthTokenProvider(this.chatSDKConfig.getAuthToken, { throwError: true })];
@@ -976,7 +983,7 @@ var OmnichannelChatSDK = /** @class */ (function () {
976
983
  _u.sent();
977
984
  _u.label = 11;
978
985
  case 11:
979
- if (!(optionalParams.liveChatContext && Object.keys(optionalParams.liveChatContext).length > 0)) return [3 /*break*/, 15];
986
+ if (!(optionalParams.liveChatContext && Object.keys(optionalParams.liveChatContext).length > 0)) return [3 /*break*/, 16];
980
987
  this.chatToken = optionalParams.liveChatContext.chatToken || {};
981
988
  this.requestId = optionalParams.liveChatContext.requestId || (0, ocsdk_1.uuidv4)();
982
989
  _u.label = 12;
@@ -998,12 +1005,21 @@ var OmnichannelChatSDK = /** @class */ (function () {
998
1005
  exceptionThrowers_1.default.throwAuthenticatedChatConversationRetrievalFailure(e_7, this.scenarioMarker, TelemetryEvent_1.default.StartChat, telemetryData);
999
1006
  return [3 /*break*/, 15];
1000
1007
  case 15:
1001
- 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];
1002
- return [4 /*yield*/, this.getChatToken(false)];
1008
+ // A persistent chat restore has a reconnectId, so the restore above skipped the key. Without it,
1009
+ // calls the service validates against the chat's session key (transcripts) return 401. Apply it
1010
+ // only after the chat is confirmed to belong to the signed-in user.
1011
+ this.sessionId = optionalParams.liveChatContext.sessionId || null;
1012
+ if (this.sessionId) {
1013
+ this.OCClient.sessionId = this.sessionId;
1014
+ }
1015
+ _u.label = 16;
1003
1016
  case 16:
1004
- _u.sent();
1005
- _u.label = 17;
1017
+ 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];
1018
+ return [4 /*yield*/, this.getChatToken(false)];
1006
1019
  case 17:
1020
+ _u.sent();
1021
+ _u.label = 18;
1022
+ case 18:
1007
1023
  if ((_l = this.chatToken) === null || _l === void 0 ? void 0 : _l.chatId) {
1008
1024
  loggerUtils_1.default.setChatId(this.chatToken.chatId || '', this.ocSdkLogger, this.acsClientLogger, this.acsAdapterLogger, this.callingSdkLogger, this.amsClientLogger, this.ic3ClientLogger);
1009
1025
  }
@@ -1024,14 +1040,14 @@ var OmnichannelChatSDK = /** @class */ (function () {
1024
1040
  else if (this.isChatReconnect && !((_o = this.chatSDKConfig.chatReconnect) === null || _o === void 0 ? void 0 : _o.disable) && !this.isPersistentChat) {
1025
1041
  sessionInitOptionalParams.reconnectId = this.reconnectId;
1026
1042
  }
1027
- 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];
1043
+ 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];
1028
1044
  return [4 /*yield*/, (0, location_1.getLocationInfo)(this.scenarioMarker, this.chatToken.chatId, this.requestId)];
1029
- case 18:
1045
+ case 19:
1030
1046
  location_2 = _u.sent();
1031
1047
  sessionInitOptionalParams.initContext.latitude = location_2.latitude;
1032
1048
  sessionInitOptionalParams.initContext.longitude = location_2.longitude;
1033
- _u.label = 19;
1034
- case 19:
1049
+ _u.label = 20;
1050
+ case 20:
1035
1051
  sessionInitPromise = function () { return __awaiter(_this, void 0, void 0, function () {
1036
1052
  var error_6, telemetryData;
1037
1053
  var _a, _b, _c;
@@ -1097,10 +1113,10 @@ var OmnichannelChatSDK = /** @class */ (function () {
1097
1113
  });
1098
1114
  }); };
1099
1115
  messagingClientPromise = function () { return __awaiter(_this, void 0, void 0, function () {
1100
- var chatAdapterConfig, error_8, telemetryData, _a, error_9, telemetryData, error_10, telemetryData, _b, error_11, telemetryData;
1101
- var _c, _d;
1102
- return __generator(this, function (_e) {
1103
- switch (_e.label) {
1116
+ var chatAdapterConfig, tokenRefresher, error_8, telemetryData, _a, error_9, telemetryData, error_10, telemetryData, _b, error_11, telemetryData;
1117
+ var _c, _d, _e;
1118
+ return __generator(this, function (_f) {
1119
+ switch (_f.label) {
1104
1120
  case 0:
1105
1121
  if (!(this.liveChatVersion === LiveChatVersion_1.default.V2)) return [3 /*break*/, 8];
1106
1122
  chatAdapterConfig = {
@@ -1110,18 +1126,22 @@ var OmnichannelChatSDK = /** @class */ (function () {
1110
1126
  environmentUrl: this.chatToken.acsEndpoint,
1111
1127
  pollingInterval: 30000
1112
1128
  };
1113
- _e.label = 1;
1129
+ _f.label = 1;
1114
1130
  case 1:
1115
- _e.trys.push([1, 3, , 4]);
1131
+ _f.trys.push([1, 3, , 4]);
1132
+ tokenRefresher = this.createChatTokenRefresher(chatAdapterConfig.token);
1133
+ this.chatTokenUnauthorizedRecovery = this.createChatTokenUnauthorizedRecovery(chatAdapterConfig.token, tokenRefresher);
1116
1134
  return [4 /*yield*/, ((_c = this.ACSClient) === null || _c === void 0 ? void 0 : _c.initialize({
1117
1135
  token: chatAdapterConfig.token,
1118
1136
  environmentUrl: chatAdapterConfig.environmentUrl,
1137
+ tokenRefresher: tokenRefresher,
1138
+ unauthorizedRecovery: (_d = this.chatTokenUnauthorizedRecovery) !== null && _d !== void 0 ? _d : undefined
1119
1139
  }))];
1120
1140
  case 2:
1121
- _e.sent();
1141
+ _f.sent();
1122
1142
  return [3 /*break*/, 4];
1123
1143
  case 3:
1124
- error_8 = _e.sent();
1144
+ error_8 = _f.sent();
1125
1145
  telemetryData = {
1126
1146
  RequestId: this.requestId,
1127
1147
  ChatId: this.chatToken.chatId,
@@ -1129,22 +1149,22 @@ var OmnichannelChatSDK = /** @class */ (function () {
1129
1149
  exceptionThrowers_1.default.throwMessagingClientInitializationFailure(error_8, this.scenarioMarker, TelemetryEvent_1.default.StartChat, telemetryData);
1130
1150
  return [3 /*break*/, 4];
1131
1151
  case 4:
1132
- _e.trys.push([4, 6, , 7]);
1152
+ _f.trys.push([4, 6, , 7]);
1133
1153
  _a = this;
1134
- return [4 /*yield*/, ((_d = this.ACSClient) === null || _d === void 0 ? void 0 : _d.joinConversation({
1154
+ return [4 /*yield*/, ((_e = this.ACSClient) === null || _e === void 0 ? void 0 : _e.joinConversation({
1135
1155
  id: chatAdapterConfig.id,
1136
1156
  threadId: chatAdapterConfig.threadId,
1137
1157
  pollingInterval: chatAdapterConfig.pollingInterval
1138
1158
  }))];
1139
1159
  case 5:
1140
- _a.conversation = (_e.sent());
1160
+ _a.conversation = (_f.sent());
1141
1161
  this.scenarioMarker.completeScenario(TelemetryEvent_1.default.StartChat, {
1142
1162
  RequestId: this.requestId,
1143
1163
  ChatId: this.chatToken.chatId
1144
1164
  });
1145
1165
  return [3 /*break*/, 7];
1146
1166
  case 6:
1147
- error_9 = _e.sent();
1167
+ error_9 = _f.sent();
1148
1168
  telemetryData = {
1149
1169
  RequestId: this.requestId,
1150
1170
  ChatId: this.chatToken.chatId,
@@ -1153,17 +1173,17 @@ var OmnichannelChatSDK = /** @class */ (function () {
1153
1173
  return [3 /*break*/, 7];
1154
1174
  case 7: return [3 /*break*/, 14];
1155
1175
  case 8:
1156
- _e.trys.push([8, 10, , 11]);
1176
+ _f.trys.push([8, 10, , 11]);
1157
1177
  return [4 /*yield*/, this.IC3Client.initialize({
1158
1178
  token: this.chatToken.token,
1159
1179
  regionGtms: this.chatToken.regionGTMS,
1160
1180
  visitor: true
1161
1181
  })];
1162
1182
  case 9:
1163
- _e.sent();
1183
+ _f.sent();
1164
1184
  return [3 /*break*/, 11];
1165
1185
  case 10:
1166
- error_10 = _e.sent();
1186
+ error_10 = _f.sent();
1167
1187
  telemetryData = {
1168
1188
  RequestId: this.requestId,
1169
1189
  ChatId: this.chatToken.chatId,
@@ -1171,18 +1191,18 @@ var OmnichannelChatSDK = /** @class */ (function () {
1171
1191
  exceptionThrowers_1.default.throwMessagingClientInitializationFailure(error_10, this.scenarioMarker, TelemetryEvent_1.default.StartChat, telemetryData);
1172
1192
  return [3 /*break*/, 11];
1173
1193
  case 11:
1174
- _e.trys.push([11, 13, , 14]);
1194
+ _f.trys.push([11, 13, , 14]);
1175
1195
  _b = this;
1176
1196
  return [4 /*yield*/, this.IC3Client.joinConversation(this.chatToken.chatId)];
1177
1197
  case 12:
1178
- _b.conversation = _e.sent();
1198
+ _b.conversation = _f.sent();
1179
1199
  this.scenarioMarker.completeScenario(TelemetryEvent_1.default.StartChat, {
1180
1200
  RequestId: this.requestId,
1181
1201
  ChatId: this.chatToken.chatId
1182
1202
  });
1183
1203
  return [3 /*break*/, 14];
1184
1204
  case 13:
1185
- error_11 = _e.sent();
1205
+ error_11 = _f.sent();
1186
1206
  telemetryData = {
1187
1207
  RequestId: this.requestId,
1188
1208
  ChatId: this.chatToken.chatId,
@@ -1225,32 +1245,32 @@ var OmnichannelChatSDK = /** @class */ (function () {
1225
1245
  }
1226
1246
  });
1227
1247
  }); };
1228
- if (!!((_r = this.chatSDKConfig.useCreateConversation) === null || _r === void 0 ? void 0 : _r.disable)) return [3 /*break*/, 21];
1248
+ if (!!((_r = this.chatSDKConfig.useCreateConversation) === null || _r === void 0 ? void 0 : _r.disable)) return [3 /*break*/, 22];
1229
1249
  return [4 /*yield*/, createConversationPromise()];
1230
- case 20:
1250
+ case 21:
1231
1251
  _u.sent();
1232
- return [3 /*break*/, 23];
1233
- case 21: return [4 /*yield*/, sessionInitPromise()];
1234
- case 22:
1235
- _u.sent(); // Await the session initialization
1236
- _u.label = 23;
1252
+ return [3 /*break*/, 24];
1253
+ case 22: return [4 /*yield*/, sessionInitPromise()];
1237
1254
  case 23:
1238
- _u.trys.push([23, 25, , 27]);
1239
- return [4 /*yield*/, Promise.all([messagingClientPromise(), attachmentClientPromise()])];
1255
+ _u.sent(); // Await the session initialization
1256
+ _u.label = 24;
1240
1257
  case 24:
1241
- _u.sent();
1242
- return [3 /*break*/, 27];
1258
+ _u.trys.push([24, 26, , 28]);
1259
+ return [4 /*yield*/, Promise.all([messagingClientPromise(), attachmentClientPromise()])];
1243
1260
  case 25:
1261
+ _u.sent();
1262
+ return [3 /*break*/, 28];
1263
+ case 26:
1244
1264
  error_5 = _u.sent();
1245
1265
  // If conversation joining fails after conversation was created, clean up the conversation
1246
1266
  // Only cleanup conversations that were freshly created (not existing ones being reconnected to)
1247
1267
  return [4 /*yield*/, this.handleConversationJoinFailure(error_5, optionalParams)];
1248
- case 26:
1268
+ case 27:
1249
1269
  // If conversation joining fails after conversation was created, clean up the conversation
1250
1270
  // Only cleanup conversations that were freshly created (not existing ones being reconnected to)
1251
1271
  _u.sent();
1252
1272
  throw error_5; // Re-throw the original error
1253
- case 27:
1273
+ case 28:
1254
1274
  if (this.isPersistentChat && !((_s = this.chatSDKConfig.persistentChat) === null || _s === void 0 ? void 0 : _s.disable)) {
1255
1275
  this.refreshTokenTimer = setInterval(function () { return __awaiter(_this, void 0, void 0, function () {
1256
1276
  var error_13;
@@ -1360,7 +1380,7 @@ var OmnichannelChatSDK = /** @class */ (function () {
1360
1380
  };
1361
1381
  OmnichannelChatSDK.prototype.internalEndChat = function () {
1362
1382
  return __awaiter(this, arguments, void 0, function (endChatOptionalParams) {
1363
- var cleanupMetadata, isReactNative, isConversationalSurveyEnabled, shouldWaitForSurvey, telemetryData, surveyStarted, error_15, error_16, telemetryData;
1383
+ var cleanupMetadata, isReactNative, isConversationalSurveyEnabled, shouldWaitForSurvey, telemetryData, surveyStarted, error_15, error_16, telemetryData, endedChatId, endedSessionId;
1364
1384
  var _a, _b, _c;
1365
1385
  if (endChatOptionalParams === void 0) { endChatOptionalParams = {}; }
1366
1386
  return __generator(this, function (_d) {
@@ -1419,12 +1439,17 @@ var OmnichannelChatSDK = /** @class */ (function () {
1419
1439
  exceptionThrowers_1.default.throwConversationClosureFailure(error_16, this.scenarioMarker, TelemetryEvent_1.default.EndChat, telemetryData);
1420
1440
  return [3 /*break*/, 11];
1421
1441
  case 10:
1422
- // Cleanup always runs, regardless of success or failure
1423
- // This ensures resources are released even if closeChat or survey waiting throws
1442
+ endedChatId = this.chatToken.chatId;
1443
+ endedSessionId = this.OCClient.sessionId || this.sessionId;
1444
+ // Keep the previous chat's key when this call had no chat to end (for example a second endChat).
1445
+ if (endedChatId && endedSessionId) {
1446
+ this.endedChatSessionKey = { chatId: endedChatId, sessionId: endedSessionId };
1447
+ }
1424
1448
  (_c = this.conversation) === null || _c === void 0 ? void 0 : _c.disconnect();
1425
1449
  this.conversation = null;
1426
1450
  this.requestId = (0, ocsdk_1.uuidv4)();
1427
1451
  this.chatToken = {};
1452
+ this.chatTokenUnauthorizedRecovery = null;
1428
1453
  this.reconnectId = null;
1429
1454
  if (this.IC3Client) {
1430
1455
  this.IC3Client.dispose();
@@ -1543,6 +1568,20 @@ var OmnichannelChatSDK = /** @class */ (function () {
1543
1568
  });
1544
1569
  });
1545
1570
  };
1571
+ /**
1572
+ * Subscribes to usable chat token renewals after the current SDK context has been updated.
1573
+ * No token or other payload is passed. Read getCurrentLiveChatContext() to persist the updated context.
1574
+ * Returns an idempotent unsubscribe function. Listener failures never affect renewal.
1575
+ * Subscriptions belong to this SDK instance and survive endChat()/startChat().
1576
+ * Subscribe before startChat() to observe restoration renewals; past notifications are not replayed.
1577
+ * Unsubscribe on host teardown or before replacing a per-chat subscription.
1578
+ */
1579
+ OmnichannelChatSDK.prototype.onChatTokenRenewed = function (listener) {
1580
+ var _this = this;
1581
+ var subscription = function () { return listener(); };
1582
+ this.chatTokenRenewedListeners.add(subscription);
1583
+ return function () { _this.chatTokenRenewedListeners.delete(subscription); };
1584
+ };
1546
1585
  OmnichannelChatSDK.prototype.getCurrentLiveChatContext = function () {
1547
1586
  return __awaiter(this, void 0, void 0, function () {
1548
1587
  var chatToken, requestId, chatSession;
@@ -1790,6 +1829,208 @@ var OmnichannelChatSDK = /** @class */ (function () {
1790
1829
  this.sessionId = this.OCClient.sessionId;
1791
1830
  }
1792
1831
  };
1832
+ /**
1833
+ * Creates the ACS token refresher used to renew the chat token before it expires. Returns undefined, which keeps
1834
+ * the existing behavior, unless renewal is enabled in the chat config, not disabled in the SDK config and
1835
+ * supported by the installed OCSDK. The refresher never throws and falls back to the current token on failure.
1836
+ */
1837
+ OmnichannelChatSDK.prototype.createChatTokenRefresher = function (initialToken) {
1838
+ var _this = this;
1839
+ var _a, _b, _c, _d, _e, _f;
1840
+ try {
1841
+ if (this.liveChatVersion !== LiveChatVersion_1.default.V2
1842
+ || ((_b = (_a = this.chatSDKConfig) === null || _a === void 0 ? void 0 : _a.chatTokenRenewal) === null || _b === void 0 ? void 0 : _b.disable) === true
1843
+ || (0, parsers_1.parseLowerCaseString)((_d = (_c = this.liveChatConfig) === null || _c === void 0 ? void 0 : _c.LcwFcbConfiguration) === null || _d === void 0 ? void 0 : _d.lcwChatTokenRenewalEnabled) !== "true"
1844
+ || typeof ((_e = this.OCClient) === null || _e === void 0 ? void 0 : _e.renewChatToken) !== "function"
1845
+ || !initialToken
1846
+ || !((_f = this.chatToken) === null || _f === void 0 ? void 0 : _f.chatId)
1847
+ || !this.requestId) {
1848
+ return undefined;
1849
+ }
1850
+ var chatId_1 = this.chatToken.chatId;
1851
+ var requestId_1 = this.requestId;
1852
+ // A reconnected chat is found by its reconnect id, not by the new request id
1853
+ var renewalId_1 = this.reconnectId || requestId_1;
1854
+ var telemetryData_1 = {
1855
+ RequestId: requestId_1,
1856
+ ChatId: chatId_1
1857
+ };
1858
+ return (0, chatTokenRenewal_1.createChatTokenRefresher)({
1859
+ initialToken: initialToken,
1860
+ chatId: chatId_1,
1861
+ isChatActive: function () { var _a; return !_this.isEndingChat && _this.requestId === requestId_1 && ((_a = _this.chatToken) === null || _a === void 0 ? void 0 : _a.chatId) === chatId_1; },
1862
+ renewChatToken: function () { return __awaiter(_this, void 0, void 0, function () {
1863
+ var renewChatTokenOptionalParams, authenticatedUserToken;
1864
+ return __generator(this, function (_a) {
1865
+ switch (_a.label) {
1866
+ case 0:
1867
+ renewChatTokenOptionalParams = {};
1868
+ return [4 /*yield*/, this.getAuthenticatedUserTokenForChatTokenRenewal()];
1869
+ case 1:
1870
+ authenticatedUserToken = _a.sent();
1871
+ if (authenticatedUserToken) {
1872
+ renewChatTokenOptionalParams.authenticatedUserToken = authenticatedUserToken;
1873
+ }
1874
+ return [2 /*return*/, this.OCClient.renewChatToken(renewalId_1, renewChatTokenOptionalParams)];
1875
+ }
1876
+ });
1877
+ }); },
1878
+ isNonRetriableStatus: function (statusCode) { return (_this.authenticatedUserToken ? chatTokenRenewal_1.authenticatedNonRetriableStatusCodes : chatTokenRenewal_1.defaultNonRetriableStatusCodes).includes(statusCode); },
1879
+ onRenewed: function (renewed) {
1880
+ var _a;
1881
+ _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 });
1882
+ _this.refreshAttachmentClientToken(chatId_1);
1883
+ _this.notifyChatTokenRenewed(requestId_1, chatId_1);
1884
+ },
1885
+ onStart: function () { return _this.scenarioMarker.startScenario(TelemetryEvent_1.default.RenewChatToken, telemetryData_1); },
1886
+ onSuccess: function () { return _this.scenarioMarker.completeScenario(TelemetryEvent_1.default.RenewChatToken, telemetryData_1); },
1887
+ onFailure: function (reason, error) {
1888
+ var exceptionDetails = {
1889
+ response: reason,
1890
+ errorObject: error !== undefined ? "".concat(error) : undefined
1891
+ };
1892
+ _this.scenarioMarker.failScenario(TelemetryEvent_1.default.RenewChatToken, __assign(__assign({}, telemetryData_1), { ExceptionDetails: JSON.stringify(exceptionDetails) }));
1893
+ }
1894
+ });
1895
+ }
1896
+ catch (_g) {
1897
+ return undefined;
1898
+ }
1899
+ };
1900
+ OmnichannelChatSDK.prototype.notifyChatTokenRenewed = function (requestId, chatId) {
1901
+ var _this = this;
1902
+ var reportFailure = function (response) {
1903
+ try {
1904
+ var telemetryData = { RequestId: requestId, ChatId: chatId };
1905
+ _this.scenarioMarker.startScenario(TelemetryEvent_1.default.ChatTokenRenewedListener, telemetryData);
1906
+ _this.scenarioMarker.failScenario(TelemetryEvent_1.default.ChatTokenRenewedListener, __assign(__assign({}, telemetryData), { ExceptionDetails: JSON.stringify({ response: response }) }));
1907
+ }
1908
+ catch (_a) {
1909
+ // Subscriber telemetry must not affect renewal or become an unhandled rejection.
1910
+ }
1911
+ };
1912
+ Array.from(this.chatTokenRenewedListeners).forEach(function (listener) {
1913
+ var _a;
1914
+ if (_this.isEndingChat || _this.requestId !== requestId || ((_a = _this.chatToken) === null || _a === void 0 ? void 0 : _a.chatId) !== chatId
1915
+ || !_this.chatTokenRenewedListeners.has(listener)) {
1916
+ return;
1917
+ }
1918
+ try {
1919
+ Promise.resolve(listener()).catch(function () { return reportFailure("ListenerRejected"); });
1920
+ }
1921
+ catch (_b) {
1922
+ reportFailure("ListenerThrew");
1923
+ }
1924
+ });
1925
+ };
1926
+ /**
1927
+ * Gives the renewed chat token to the attachment client, which keeps the token it was initialized with and uses
1928
+ * it for every upload and download. Runs in the background and never throws: on failure, attachments keep using
1929
+ * the previous token as they did before renewal existed.
1930
+ */
1931
+ OmnichannelChatSDK.prototype.refreshAttachmentClientToken = function (chatId) {
1932
+ var _this = this;
1933
+ try {
1934
+ var amsClient_1 = this.AMSClient;
1935
+ var chatToken_1 = this.chatToken;
1936
+ if (!this.isAMSClientAllowed
1937
+ || this.AMSClientLoadCurrentState !== AMSClientLoadStates_1.AMSClientLoadStates.LOADED
1938
+ || !amsClient_1
1939
+ || typeof amsClient_1.initialize !== "function"
1940
+ || (chatToken_1 === null || chatToken_1 === void 0 ? void 0 : chatToken_1.chatId) !== chatId
1941
+ || !chatToken_1.token) {
1942
+ return;
1943
+ }
1944
+ var telemetryData_2 = {
1945
+ RequestId: this.requestId,
1946
+ ChatId: chatId
1947
+ };
1948
+ this.scenarioMarker.startScenario(TelemetryEvent_1.default.RefreshAttachmentClientToken, telemetryData_2);
1949
+ Promise.resolve()
1950
+ .then(function () { return amsClient_1.initialize({ chatToken: chatToken_1 }); })
1951
+ .then(function () {
1952
+ _this.scenarioMarker.completeScenario(TelemetryEvent_1.default.RefreshAttachmentClientToken, telemetryData_2);
1953
+ }, function (error) {
1954
+ _this.scenarioMarker.failScenario(TelemetryEvent_1.default.RefreshAttachmentClientToken, __assign(__assign({}, telemetryData_2), { ExceptionDetails: JSON.stringify({ errorObject: "".concat(error) }) }));
1955
+ })
1956
+ .catch(function () {
1957
+ // Telemetry failures must not surface
1958
+ });
1959
+ }
1960
+ catch (_a) {
1961
+ // Attachments keep using the previous token
1962
+ }
1963
+ };
1964
+ /**
1965
+ * Creates the recovery for chat requests that fail with 401 while the chat token has not
1966
+ * expired. Returns null, which keeps the existing behavior, unless chat token renewal is enabled and recovery is
1967
+ * not disabled in the SDK config.
1968
+ */
1969
+ OmnichannelChatSDK.prototype.createChatTokenUnauthorizedRecovery = function (initialToken, tokenRefresher) {
1970
+ var _this = this;
1971
+ var _a, _b, _c;
1972
+ try {
1973
+ if (!tokenRefresher
1974
+ || ((_b = (_a = this.chatSDKConfig) === null || _a === void 0 ? void 0 : _a.chatTokenRenewal) === null || _b === void 0 ? void 0 : _b.disableUnauthorizedRecovery) === true
1975
+ || !initialToken) {
1976
+ return null;
1977
+ }
1978
+ var telemetryData_3 = {
1979
+ RequestId: this.requestId,
1980
+ ChatId: (_c = this.chatToken) === null || _c === void 0 ? void 0 : _c.chatId
1981
+ };
1982
+ return (0, chatTokenUnauthorizedRecovery_1.createChatTokenUnauthorizedRecovery)({
1983
+ initialToken: initialToken,
1984
+ refreshToken: tokenRefresher,
1985
+ onStart: function () { return _this.scenarioMarker.startScenario(TelemetryEvent_1.default.ChatTokenUnauthorizedRecovery, telemetryData_3); },
1986
+ onSuccess: function (_source, usedExistingToken) {
1987
+ if (!usedExistingToken) {
1988
+ _this.scenarioMarker.completeScenario(TelemetryEvent_1.default.ChatTokenUnauthorizedRecovery, telemetryData_3);
1989
+ }
1990
+ },
1991
+ onFailure: function (source, reason) {
1992
+ _this.scenarioMarker.failScenario(TelemetryEvent_1.default.ChatTokenUnauthorizedRecovery, __assign(__assign({}, telemetryData_3), { ExceptionDetails: JSON.stringify({ response: reason, source: source }) }));
1993
+ }
1994
+ });
1995
+ }
1996
+ catch (_d) {
1997
+ return null;
1998
+ }
1999
+ };
2000
+ /**
2001
+ * Returns the token of the authenticated user to renew the chat token with, refreshed from the auth token
2002
+ * provider when possible because the token used to start the chat may have expired. Returns undefined for
2003
+ * unauthenticated chats.
2004
+ */
2005
+ OmnichannelChatSDK.prototype.getAuthenticatedUserTokenForChatTokenRenewal = function () {
2006
+ return __awaiter(this, void 0, void 0, function () {
2007
+ var token, _a;
2008
+ var _b;
2009
+ return __generator(this, function (_c) {
2010
+ switch (_c.label) {
2011
+ case 0:
2012
+ if (!this.authenticatedUserToken) {
2013
+ return [2 /*return*/, undefined];
2014
+ }
2015
+ if (!(typeof ((_b = this.chatSDKConfig) === null || _b === void 0 ? void 0 : _b.getAuthToken) === "function")) return [3 /*break*/, 4];
2016
+ _c.label = 1;
2017
+ case 1:
2018
+ _c.trys.push([1, 3, , 4]);
2019
+ return [4 /*yield*/, this.chatSDKConfig.getAuthToken()];
2020
+ case 2:
2021
+ token = _c.sent();
2022
+ if (typeof token === "string" && token.trim().length > 0) {
2023
+ return [2 /*return*/, token];
2024
+ }
2025
+ return [3 /*break*/, 4];
2026
+ case 3:
2027
+ _a = _c.sent();
2028
+ return [3 /*break*/, 4];
2029
+ case 4: return [2 /*return*/, this.authenticatedUserToken];
2030
+ }
2031
+ });
2032
+ });
2033
+ };
1793
2034
  OmnichannelChatSDK.prototype.getCallingToken = function () {
1794
2035
  return __awaiter(this, void 0, void 0, function () {
1795
2036
  return __generator(this, function (_a) {
@@ -2628,7 +2869,8 @@ var OmnichannelChatSDK = /** @class */ (function () {
2628
2869
  };
2629
2870
  OmnichannelChatSDK.prototype.emailLiveChatTranscript = function (body_1) {
2630
2871
  return __awaiter(this, arguments, void 0, function (body, optionalParams) {
2631
- var emailTranscriptOptionalParams, requestId, chatToken, chatId, sessionId, emailRequestBody, error_27;
2872
+ var emailTranscriptOptionalParams, requestId, chatToken, chatId, requestSessionKey, emailRequestBody_1, error_27;
2873
+ var _this = this;
2632
2874
  var _a;
2633
2875
  if (optionalParams === void 0) { optionalParams = {}; }
2634
2876
  return __generator(this, function (_b) {
@@ -2638,16 +2880,12 @@ var OmnichannelChatSDK = /** @class */ (function () {
2638
2880
  requestId = this.requestId;
2639
2881
  chatToken = this.chatToken;
2640
2882
  chatId = chatToken.chatId;
2641
- sessionId = this.sessionId;
2642
2883
  if (optionalParams.liveChatContext) {
2643
2884
  requestId = optionalParams.liveChatContext.requestId;
2644
2885
  chatToken = optionalParams.liveChatContext.chatToken;
2645
2886
  chatId = chatToken.chatId;
2646
2887
  }
2647
- if ((_a = optionalParams.liveChatContext) === null || _a === void 0 ? void 0 : _a.sessionId) {
2648
- sessionId = optionalParams.liveChatContext.sessionId;
2649
- this.OCClient.sessionId = sessionId;
2650
- }
2888
+ requestSessionKey = ((_a = optionalParams.liveChatContext) === null || _a === void 0 ? void 0 : _a.sessionId) || this.getEndedChatSessionKey(chatId);
2651
2889
  this.scenarioMarker.startScenario(TelemetryEvent_1.default.EmailLiveChatTranscript, {
2652
2890
  RequestId: requestId,
2653
2891
  ChatId: chatId
@@ -2661,18 +2899,15 @@ var OmnichannelChatSDK = /** @class */ (function () {
2661
2899
  if (this.authenticatedUserToken) {
2662
2900
  emailTranscriptOptionalParams.authenticatedUserToken = this.authenticatedUserToken;
2663
2901
  }
2664
- emailRequestBody = {
2902
+ emailRequestBody_1 = {
2665
2903
  ChatId: chatId,
2666
2904
  EmailAddress: body.emailAddress,
2667
2905
  DefaultAttachmentMessage: body.attachmentMessage,
2668
2906
  CustomerLocale: body.locale || (0, locale_1.getLocaleStringFromId)(this.localeId)
2669
2907
  };
2670
- return [4 /*yield*/, this.OCClient.emailTranscript(requestId, chatToken.token, emailRequestBody, emailTranscriptOptionalParams)];
2908
+ return [4 /*yield*/, this.withRequestSessionKey(requestSessionKey, function () { return _this.OCClient.emailTranscript(requestId, chatToken.token, emailRequestBody_1, emailTranscriptOptionalParams); })];
2671
2909
  case 2:
2672
2910
  _b.sent();
2673
- if (this.sessionId) {
2674
- this.OCClient.sessionId = this.sessionId;
2675
- }
2676
2911
  this.scenarioMarker.completeScenario(TelemetryEvent_1.default.EmailLiveChatTranscript, {
2677
2912
  RequestId: requestId,
2678
2913
  ChatId: chatId
@@ -2693,7 +2928,8 @@ var OmnichannelChatSDK = /** @class */ (function () {
2693
2928
  };
2694
2929
  OmnichannelChatSDK.prototype.getLiveChatTranscript = function () {
2695
2930
  return __awaiter(this, arguments, void 0, function (optionalParams) {
2696
- var getChatTranscriptOptionalParams, requestId, chatToken, chatId, sessionId, transcriptResponse, error_28, telemetryData;
2931
+ var getChatTranscriptOptionalParams, requestId, chatToken, chatId, requestSessionKey, transcriptResponse, error_28, telemetryData;
2932
+ var _this = this;
2697
2933
  var _a, _b;
2698
2934
  if (optionalParams === void 0) { optionalParams = {}; }
2699
2935
  return __generator(this, function (_c) {
@@ -2703,7 +2939,6 @@ var OmnichannelChatSDK = /** @class */ (function () {
2703
2939
  requestId = this.requestId;
2704
2940
  chatToken = this.chatToken;
2705
2941
  chatId = chatToken.chatId;
2706
- sessionId = this.sessionId;
2707
2942
  if (optionalParams.liveChatContext) {
2708
2943
  if (this.isPersistentChat && !((_a = this.chatSDKConfig.persistentChat) === null || _a === void 0 ? void 0 : _a.disable)) {
2709
2944
  requestId = this.requestId || optionalParams.liveChatContext.requestId;
@@ -2715,10 +2950,6 @@ var OmnichannelChatSDK = /** @class */ (function () {
2715
2950
  }
2716
2951
  chatId = chatToken.chatId;
2717
2952
  }
2718
- if ((_b = optionalParams.liveChatContext) === null || _b === void 0 ? void 0 : _b.sessionId) {
2719
- sessionId = optionalParams.liveChatContext.sessionId;
2720
- this.OCClient.sessionId = sessionId;
2721
- }
2722
2953
  if (!chatId) {
2723
2954
  throw new ChatSDKError_1.ChatSDKError(ChatSDKError_1.ChatSDKErrorName.LiveChatTranscriptRetrievalFailure, undefined, {
2724
2955
  response: ChatSDKError_1.ChatSDKErrorName.LiveChatTranscriptRetrievalFailure,
@@ -2732,18 +2963,16 @@ var OmnichannelChatSDK = /** @class */ (function () {
2732
2963
  if (!this.isInitialized) {
2733
2964
  exceptionThrowers_1.default.throwUninitializedChatSDK(this.scenarioMarker, TelemetryEvent_1.default.GetLiveChatTranscript);
2734
2965
  }
2966
+ requestSessionKey = ((_b = optionalParams.liveChatContext) === null || _b === void 0 ? void 0 : _b.sessionId) || this.getEndedChatSessionKey(chatId);
2735
2967
  _c.label = 1;
2736
2968
  case 1:
2737
2969
  _c.trys.push([1, 3, , 4]);
2738
2970
  if (this.authenticatedUserToken) {
2739
2971
  getChatTranscriptOptionalParams.authenticatedUserToken = this.authenticatedUserToken;
2740
2972
  }
2741
- return [4 /*yield*/, this.OCClient.getChatTranscripts(requestId, chatToken.chatId, chatToken.token, getChatTranscriptOptionalParams)];
2973
+ return [4 /*yield*/, this.withRequestSessionKey(requestSessionKey, function () { return _this.OCClient.getChatTranscripts(requestId, chatToken.chatId, chatToken.token, getChatTranscriptOptionalParams); })];
2742
2974
  case 2:
2743
2975
  transcriptResponse = _c.sent();
2744
- if (this.sessionId) {
2745
- this.OCClient.sessionId = this.sessionId;
2746
- }
2747
2976
  this.scenarioMarker.completeScenario(TelemetryEvent_1.default.GetLiveChatTranscript, {
2748
2977
  RequestId: requestId,
2749
2978
  ChatId: chatId
@@ -2762,6 +2991,30 @@ var OmnichannelChatSDK = /** @class */ (function () {
2762
2991
  });
2763
2992
  });
2764
2993
  };
2994
+ /**
2995
+ * Returns the ended chat's session key when the call targets that chat, or null.
2996
+ */
2997
+ OmnichannelChatSDK.prototype.getEndedChatSessionKey = function (chatId) {
2998
+ var _a;
2999
+ return chatId && ((_a = this.endedChatSessionKey) === null || _a === void 0 ? void 0 : _a.chatId) === chatId ? this.endedChatSessionKey.sessionId : null;
3000
+ };
3001
+ /**
3002
+ * Sends the session key on one OCSDK request without leaving it on the shared client. OCSDK copies the
3003
+ * key into the request headers before its first await, so the previous key is restored before the HTTP wait.
3004
+ */
3005
+ OmnichannelChatSDK.prototype.withRequestSessionKey = function (sessionKey, request) {
3006
+ if (!sessionKey) {
3007
+ return request();
3008
+ }
3009
+ var previousSessionKey = this.OCClient.sessionId;
3010
+ this.OCClient.sessionId = sessionKey;
3011
+ try {
3012
+ return request();
3013
+ }
3014
+ finally {
3015
+ this.OCClient.sessionId = previousSessionKey;
3016
+ }
3017
+ };
2765
3018
  OmnichannelChatSDK.prototype.createChatAdapter = function () {
2766
3019
  return __awaiter(this, arguments, void 0, function (optionalParams) {
2767
3020
  var protocol, supportedChatAdapterProtocols, options, fileManager;