@xapp/chat-widget 1.53.2 → 1.54.0

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/dist/index.js CHANGED
@@ -2031,12 +2031,20 @@ function executeAction(text, token) {
2031
2031
  }; };
2032
2032
  }
2033
2033
 
2034
+ /**
2035
+ * This is not used anymore. It was part of the handshake with the legacy "chat server"
2036
+ *
2037
+ * @param token
2038
+ * @returns
2039
+ */
2034
2040
  function receiveToken(token) {
2035
2041
  return {
2036
2042
  type: "receiveToken",
2037
2043
  detail: {
2038
2044
  token: token,
2039
- timestamp: +Date()
2045
+ timestamp: +Date(),
2046
+ type: "receiveToken",
2047
+ user: undefined
2040
2048
  }
2041
2049
  };
2042
2050
  }
@@ -2155,6 +2163,26 @@ function setConnectionStatus(status) {
2155
2163
  };
2156
2164
  }
2157
2165
 
2166
+ function sendBargeIn(agentName) {
2167
+ return function (chatServer) { return function () {
2168
+ chatServer.bargeIn(agentName, function (err) {
2169
+ if (err) {
2170
+ log(err);
2171
+ }
2172
+ });
2173
+ }; };
2174
+ }
2175
+
2176
+ function sendBargeOut() {
2177
+ return function (chatServer) { return function () {
2178
+ chatServer.bargeOut(function (err) {
2179
+ if (err) {
2180
+ log(err);
2181
+ }
2182
+ });
2183
+ }; };
2184
+ }
2185
+
2158
2186
  function reset() {
2159
2187
  return {
2160
2188
  type: "reset"
@@ -2169,6 +2197,14 @@ var LogChat = /** @class */ (function () {
2169
2197
  function LogChat(inner) {
2170
2198
  this.inner = inner;
2171
2199
  }
2200
+ LogChat.prototype.bargeOut = function (cb) {
2201
+ log("CLIENT: bargeOut");
2202
+ this.inner.bargeOut(cb);
2203
+ };
2204
+ LogChat.prototype.bargeIn = function (agentName, cb) {
2205
+ log("CLIENT: bargeIn: ".concat(agentName));
2206
+ this.inner.bargeIn(agentName, cb);
2207
+ };
2172
2208
  LogChat.prototype.init = function (dispatch) {
2173
2209
  this.inner.init(dispatch);
2174
2210
  };
@@ -2639,7 +2675,7 @@ function parseSuggestionsResponse(response, direction) {
2639
2675
  }, []);
2640
2676
  }
2641
2677
 
2642
- /*! *****************************************************************************
2678
+ /******************************************************************************
2643
2679
  Copyright (c) Microsoft Corporation.
2644
2680
 
2645
2681
  Permission to use, copy, modify, and/or distribute this software for any
@@ -2670,7 +2706,7 @@ function __generator(thisArg, body) {
2670
2706
  function verb(n) { return function (v) { return step([n, v]); }; }
2671
2707
  function step(op) {
2672
2708
  if (f) throw new TypeError("Generator is already executing.");
2673
- while (_) try {
2709
+ while (g && (g = 0, op[0] && (_ = 0)), _) try {
2674
2710
  if (f = 1, y && (t = op[0] & 2 ? y["return"] : op[0] ? y["throw"] || ((t = y["return"]) && t.call(y), 0) : y.next) && !(t = t.call(y, op[1])).done) return t;
2675
2711
  if (y = 0, t) op = [op[0] & 2, t.value];
2676
2712
  switch (op[0]) {
@@ -3241,6 +3277,20 @@ var StentorDirectChat = /** @class */ (function () {
3241
3277
  });
3242
3278
  });
3243
3279
  };
3280
+ StentorDirectChat.prototype.bargeOut = function (_cb) {
3281
+ return __awaiter$1(this, void 0, void 0, function () {
3282
+ return __generator$1(this, function (_a) {
3283
+ throw new Error("Method not implemented: bargeOut");
3284
+ });
3285
+ });
3286
+ };
3287
+ StentorDirectChat.prototype.bargeIn = function (_agentName, _cb) {
3288
+ return __awaiter$1(this, void 0, void 0, function () {
3289
+ return __generator$1(this, function (_a) {
3290
+ throw new Error("Method not implemented: bargeIn");
3291
+ });
3292
+ });
3293
+ };
3244
3294
  StentorDirectChat.prototype.getBot = function (user) {
3245
3295
  var _a;
3246
3296
  var bot = (_a = this.options) === null || _a === void 0 ? void 0 : _a.bot;
@@ -3560,12 +3610,16 @@ var StentorLocalChat = /** @class */ (function () {
3560
3610
  };
3561
3611
  StentorLocalChat.prototype.dispose = function () {
3562
3612
  };
3613
+ StentorLocalChat.prototype.bargeOut = function () {
3614
+ };
3615
+ StentorLocalChat.prototype.bargeIn = function () {
3616
+ };
3563
3617
  return StentorLocalChat;
3564
3618
  }());
3565
3619
 
3566
3620
  /*! Copyright (c) 2022, XAPPmedia */
3567
3621
  var PERMISSION_QUESTION_EXPIRATION_MS = 300000; // 5 minutes
3568
- function requestFromMessage(message, userId, isNewSession, sessionId, accessToken, attributes) {
3622
+ function requestFromMessage(message, userId, isNewSession, sessionId, accessToken, attributes, visitorInfo) {
3569
3623
  var _a, _b, _c, _d;
3570
3624
  var request;
3571
3625
  var now = new Date().getTime();
@@ -3591,13 +3645,13 @@ function requestFromMessage(message, userId, isNewSession, sessionId, accessToke
3591
3645
  var expired = now - permissionRequest.time > PERMISSION_QUESTION_EXPIRATION_MS;
3592
3646
  var text = (_d = message.msg.text) === null || _d === void 0 ? void 0 : _d.toLowerCase();
3593
3647
  var granted = !expired;
3594
- var userProfile = { id: this._userId };
3648
+ var userProfile = { id: userId };
3595
3649
  if (!expired) {
3596
3650
  if (permissionRequest.type === "EMAIL") {
3597
3651
  var isEmail = looksLikeEmail(text);
3598
3652
  granted = isEmail;
3599
- userProfile.email = this.visitorInfo.email;
3600
- userProfile.name = this.visitorInfo.displayName;
3653
+ userProfile.email = visitorInfo.email;
3654
+ userProfile.name = visitorInfo.displayName;
3601
3655
  this.visitorInfo.email = text;
3602
3656
  }
3603
3657
  if (permissionRequest.type === "LOCATION_PRECISE") {
@@ -3613,8 +3667,8 @@ function requestFromMessage(message, userId, isNewSession, sessionId, accessToke
3613
3667
  request = {
3614
3668
  type: "PERMISSION_GRANT",
3615
3669
  rawQuery: message.msg.text,
3616
- sessionId: this._sessionId,
3617
- userId: this._userId,
3670
+ sessionId: sessionId,
3671
+ userId: userId,
3618
3672
  isNewSession: false,
3619
3673
  granted: granted,
3620
3674
  userProfile: userProfile,
@@ -3622,13 +3676,13 @@ function requestFromMessage(message, userId, isNewSession, sessionId, accessToke
3622
3676
  platform: "stentor-platform",
3623
3677
  channel: "widget",
3624
3678
  accessToken: accessToken,
3625
- attributes: attributes
3679
+ attributes: attributes,
3626
3680
  };
3627
3681
  }
3628
3682
  else if (message.type === "custom") {
3629
3683
  request = __assign(__assign({}, JSON.parse(message.payload)), {
3630
3684
  // token: message.msg.token,
3631
- sessionId: this._sessionId, userId: this._userId, isNewSession: false,
3685
+ sessionId: sessionId, userId: userId, isNewSession: false,
3632
3686
  // intentId: "OptionSelect",
3633
3687
  platform: "stentor-platform", channel: "widget", accessToken: accessToken, attributes: attributes });
3634
3688
  }
@@ -3636,28 +3690,28 @@ function requestFromMessage(message, userId, isNewSession, sessionId, accessToke
3636
3690
  request = {
3637
3691
  type: "OPTION_SELECT_REQUEST",
3638
3692
  token: message.msg.token,
3639
- sessionId: this._sessionId,
3640
- userId: this._userId,
3693
+ sessionId: sessionId,
3694
+ userId: userId,
3641
3695
  isNewSession: false,
3642
3696
  intentId: "OptionSelect",
3643
3697
  platform: "stentor-platform",
3644
3698
  channel: "widget",
3645
3699
  accessToken: accessToken,
3646
- attributes: attributes
3700
+ attributes: attributes,
3647
3701
  };
3648
3702
  }
3649
3703
  else {
3650
3704
  request = {
3651
3705
  type: "INTENT_REQUEST",
3652
3706
  rawQuery: message.msg.text,
3653
- sessionId: this._sessionId,
3654
- userId: this._userId,
3707
+ sessionId: sessionId,
3708
+ userId: userId,
3655
3709
  isNewSession: false,
3656
3710
  intentId: "NLU_RESULT_PLACEHOLDER",
3657
3711
  platform: "stentor-platform",
3658
3712
  channel: "widget",
3659
3713
  accessToken: accessToken,
3660
- attributes: attributes
3714
+ attributes: attributes,
3661
3715
  };
3662
3716
  }
3663
3717
  }
@@ -3707,29 +3761,37 @@ var StentorRouterChat = /** @class */ (function () {
3707
3761
  this.handlers = {};
3708
3762
  this.config = config;
3709
3763
  this.options = options;
3710
- // Dig out the path parameters. Put them into the attributes.
3764
+ // Dig out the path parameters. Put them into the attributes.
3711
3765
  // The WS url is the barebone domain.
3712
3766
  var url = new URL(this.config.url);
3713
3767
  var urlPath = (_a = url.pathname) === null || _a === void 0 ? void 0 : _a.split("/");
3714
- // eslint-disable-next-line @typescript-eslint/no-explicit-any
3715
- this.isAdmin = (url.searchParams.get('isAdmin') || window.xaIsAdmin) === "true";
3768
+ var locationUrl = new URL(window.location.href);
3769
+ this.isAdmin = locationUrl.searchParams.get("isAdmin") === "true";
3716
3770
  this.serverUrl = "".concat(url.origin);
3717
3771
  if (urlPath && urlPath.length > 1) {
3718
3772
  this.serverUrl = "".concat(this.serverUrl, "/").concat(urlPath[1]); // the first path (after the initial "") is the "dev" or "prod"
3719
- this.urlAttributes.path = urlPath.slice(2);
3773
+ this.urlAttributes.path = urlPath.slice(1);
3720
3774
  }
3721
- log("WS url: ".concat(this.serverUrl, " attributes: ").concat(JSON.stringify(this.attributes)));
3722
- // this.configurableMessages = options.configurableMessages;
3775
+ log("WS url: ".concat(this.serverUrl, " isAdmin: ").concat(this.isAdmin, " attributes: ").concat(JSON.stringify(this.attributes)));
3776
+ this.configurableMessages = getConfigurableMessagesConfig(options.configurableMessages);
3723
3777
  }
3724
3778
  StentorRouterChat.prototype.init = function (dispatch) {
3725
3779
  var _this = this;
3726
- // Fire up the WebSocket
3727
- this.autoReconnect(this.wsCreate.bind(this));
3728
3780
  this.dispatch = dispatch;
3781
+ this.setAccountStatus("offline");
3729
3782
  // Register "handlers" for the incoming events
3730
- this.handlers["account_status"] = function (_data, _sender) {
3731
- // Register the "endpoint" with the server (send visitor data)
3732
- _this.emit("connection update");
3783
+ this.handlers["connection update"] = function (data, _sender) {
3784
+ log("Connection update received. Session created: ".concat(data.sessionCreated, " Error: ").concat(data.errorMessage || ""));
3785
+ if (data.sessionCreated) {
3786
+ _this.sessionCreated = true;
3787
+ }
3788
+ else {
3789
+ // Shut down
3790
+ _this.dispatch(setAccountStatus("offline"));
3791
+ _this.dispatch(setConnectionStatus("offline"));
3792
+ }
3793
+ };
3794
+ this.handlers["account status"] = function (_data, _sender) {
3733
3795
  dispatch({
3734
3796
  type: "account_status",
3735
3797
  detail: {
@@ -3738,6 +3800,11 @@ var StentorRouterChat = /** @class */ (function () {
3738
3800
  },
3739
3801
  });
3740
3802
  };
3803
+ this.handlers["failure"] = function (data, sender) {
3804
+ err("Router says something failed: type: ".concat(data.type, " tries: ").concat(data.tries, " error: ").concat(data.error));
3805
+ var _a = _this.configurableMessages[data.tries], retry = _a.retry, delay = _a.delay, text = _a.text;
3806
+ _this.sendFailureMessage(retry, data.delay || delay, text, sender);
3807
+ };
3741
3808
  this.handlers["new message"] = function (data, sender) {
3742
3809
  // Because the router's internal message format is Stentor channel compatible.
3743
3810
  // So the data is either a stentor Request (from widget) or a stentor Response (from bot)
@@ -3763,7 +3830,7 @@ var StentorRouterChat = /** @class */ (function () {
3763
3830
  displayName: sender.displayName || sender.email || sender.userId,
3764
3831
  nick: senderToNick(sender),
3765
3832
  },
3766
- msg: message,
3833
+ msg: message.msg,
3767
3834
  timestamp: +new Date(),
3768
3835
  },
3769
3836
  });
@@ -3829,27 +3896,30 @@ var StentorRouterChat = /** @class */ (function () {
3829
3896
  _this.dispatch(setAccountStatus("online"));
3830
3897
  _this.dispatch(setConnectionStatus("online"));
3831
3898
  };
3832
- this.handlers["reconnect_failed"] = function (_data) {
3899
+ this.handlers["reconnect failed"] = function (_data) {
3833
3900
  _this.dispatch(setAccountStatus("offline"));
3834
3901
  _this.dispatch(setConnectionStatus("offline"));
3835
3902
  };
3836
- this.handlers["reconnect_error"] = function (_data) {
3903
+ this.handlers["reconnect error"] = function (_data) {
3837
3904
  _this.dispatch(setAccountStatus("offline"));
3838
3905
  };
3839
- this.setAccountStatus("offline");
3906
+ // pretend we are online. The emit() will connect
3907
+ this.setAccountStatus("online");
3908
+ this.setConnectionStatus("online");
3840
3909
  };
3841
3910
  StentorRouterChat.prototype.autoReconnect = function (wsCreate) {
3842
3911
  var _this = this;
3843
- var setStatus = this.setAccountStatus.bind(this);
3912
+ var setActStatus = this.setAccountStatus.bind(this);
3913
+ var setConnStatus = this.setConnectionStatus.bind(this);
3844
3914
  function startReconnecting() {
3845
- setStatus("offline");
3846
3915
  var interval = setInterval(function () {
3847
3916
  log("Re-creating WS connection");
3848
3917
  var ws = wsCreate();
3849
3918
  ws.onopen = function () {
3850
3919
  log("Re-opened WS connection");
3851
3920
  // We are connected
3852
- setStatus("online");
3921
+ setActStatus("online");
3922
+ setConnStatus("online");
3853
3923
  ws.onclose = startReconnecting;
3854
3924
  clearInterval(interval);
3855
3925
  };
@@ -3862,26 +3932,77 @@ var StentorRouterChat = /** @class */ (function () {
3862
3932
  log("Opened WS connection");
3863
3933
  // We are connected
3864
3934
  _this.setAccountStatus("online");
3935
+ _this.setConnectionStatus("online");
3865
3936
  };
3866
3937
  };
3867
3938
  StentorRouterChat.prototype.wsCreate = function () {
3868
- this.ws = new WebSocket("".concat(this.serverUrl, "?userId=").concat(this._userId));
3869
- this.ws.onmessage = function (data) {
3870
- console.log("SERVER says: ".concat(JSON.stringify(data)));
3871
- // const message: RouterMessage = JSON.parse(data);
3872
- // this.handlers[message.event](message.data, message.sender);
3939
+ var _this = this;
3940
+ this.setConnectionStatus("pending");
3941
+ this.ws = new WebSocket("".concat(this.serverUrl, "?userId=").concat(this._userId, "&isAdmin=").concat(this.isAdmin));
3942
+ this.ws.onerror = function (ev) {
3943
+ var _a;
3944
+ log("Error in WS connection. Type: ".concat(!ev ? "?" : ev.type, " Ready State: ").concat((_a = _this.ws) === null || _a === void 0 ? void 0 : _a.readyState));
3945
+ _this.setConnectionStatus("pending");
3946
+ };
3947
+ this.ws.onmessage = function (me) {
3948
+ log("ROUTER says: ".concat(me.data));
3949
+ var message = JSON.parse(me.data);
3950
+ var handler = _this.handlers[message.event];
3951
+ if (handler) {
3952
+ _this.handlers[message.event](message.data, message.sender);
3953
+ }
3954
+ else {
3955
+ log("Unknown router message event: ".concat(message.event));
3956
+ }
3873
3957
  };
3874
3958
  return this.ws;
3875
3959
  };
3960
+ StentorRouterChat.prototype.checkConnection = function () {
3961
+ return this.ws.readyState === WebSocket.OPEN;
3962
+ };
3876
3963
  StentorRouterChat.prototype.emit = function (event, data) {
3877
- var payloadData = JSON.stringify({ event: event, data: data, sender: this.visitorInfo });
3878
- log("Widget says: ".concat(payloadData));
3879
- this.ws.send(payloadData);
3964
+ return __awaiter$1(this, void 0, void 0, function () {
3965
+ var payloadData;
3966
+ var _this = this;
3967
+ return __generator$1(this, function (_a) {
3968
+ switch (_a.label) {
3969
+ case 0:
3970
+ payloadData = JSON.stringify({
3971
+ event: event,
3972
+ data: data,
3973
+ sender: this.visitorInfo,
3974
+ sessionId: this._sessionId,
3975
+ });
3976
+ log("Widget says: ".concat(payloadData));
3977
+ if (!this.ws) {
3978
+ // Fire up the WebSocket
3979
+ this.autoReconnect(this.wsCreate.bind(this));
3980
+ }
3981
+ return [4 /*yield*/, waitFor(this.checkConnection.bind(this), 500, 5000, "connection")
3982
+ .then(function (t) {
3983
+ if (t > 0) {
3984
+ log("Connection is ready in ".concat(t, " ms"));
3985
+ }
3986
+ _this.ws.send(payloadData);
3987
+ })
3988
+ .catch(function (t) {
3989
+ console.log("Connection wait timed out in ".concat(t, " ms"));
3990
+ })];
3991
+ case 1:
3992
+ _a.sent();
3993
+ return [2 /*return*/];
3994
+ }
3995
+ });
3996
+ });
3880
3997
  };
3881
3998
  StentorRouterChat.prototype.setAccountStatus = function (status) {
3882
3999
  log("SERVER account_status: ".concat(JSON.stringify(status)));
3883
4000
  this.dispatch(setAccountStatus(status));
3884
4001
  };
4002
+ StentorRouterChat.prototype.setConnectionStatus = function (status) {
4003
+ log("SERVER: connection_update: ".concat(JSON.stringify(status)));
4004
+ this.dispatch(setConnectionStatus(status));
4005
+ };
3885
4006
  StentorRouterChat.prototype.sendOfflineMsg = function (_, cb) {
3886
4007
  cb();
3887
4008
  };
@@ -3898,11 +4019,48 @@ var StentorRouterChat = /** @class */ (function () {
3898
4019
  });
3899
4020
  });
3900
4021
  };
4022
+ StentorRouterChat.prototype.sendFailureMessage = function (retry, delay, text, sender) {
4023
+ this.dispatch({
4024
+ type: "chat",
4025
+ detail: {
4026
+ type: "chat.typing",
4027
+ user: {
4028
+ nick: senderToNick(sender),
4029
+ },
4030
+ typing: false,
4031
+ timestamp: +new Date(),
4032
+ },
4033
+ });
4034
+ this.dispatch({
4035
+ type: "chat",
4036
+ detail: {
4037
+ type: "chat.failureMsg",
4038
+ user: {
4039
+ nick: senderToNick(sender)
4040
+ },
4041
+ failureMsg: { retry: retry, delay: delay, text: text },
4042
+ timestamp: +new Date()
4043
+ }
4044
+ });
4045
+ };
4046
+ StentorRouterChat.prototype.checkSession = function () {
4047
+ return this.sessionCreated;
4048
+ };
3901
4049
  StentorRouterChat.prototype.sendChatMsgRequest = function (serviceRequest, cb) {
3902
4050
  return __awaiter$1(this, void 0, void 0, function () {
4051
+ var _this = this;
3903
4052
  return __generator$1(this, function (_a) {
3904
4053
  switch (_a.label) {
3905
- case 0: return [4 /*yield*/, this.postMessage(serviceRequest)];
4054
+ case 0: return [4 /*yield*/, waitFor(this.checkSession.bind(this), 500, 5000, "session creation")
4055
+ .then(function (t) {
4056
+ if (t > 0) {
4057
+ log("Session creation is ready in ".concat(t, " ms"));
4058
+ }
4059
+ _this.postMessage(serviceRequest);
4060
+ })
4061
+ .catch(function (t) {
4062
+ console.log("Session creation wait timed out in ".concat(t, " ms"));
4063
+ })];
3906
4064
  case 1:
3907
4065
  _a.sent();
3908
4066
  cb();
@@ -3911,23 +4069,24 @@ var StentorRouterChat = /** @class */ (function () {
3911
4069
  });
3912
4070
  });
3913
4071
  };
3914
- StentorRouterChat.prototype.sendTyping = function (isTyping) {
3915
- this.emit(isTyping ? "typing" : "stop typing");
4072
+ StentorRouterChat.prototype.sendTyping = function (_isTyping) {
4073
+ // TODO: Is this too much traffic?
4074
+ // this.emit(isTyping ? "typing" : "stop typing");
3916
4075
  };
3917
4076
  StentorRouterChat.prototype.setVisitorInfo = function (visitorInfoMessage, cb) {
3918
- log("Visitor Info Mesage = ".concat(visitorInfoMessage));
4077
+ log("Visitor Info Message = ".concat(JSON.stringify(visitorInfoMessage)));
3919
4078
  this.visitorInfo = {
3920
4079
  deviceId: "Widget",
3921
4080
  userId: visitorInfoMessage.userId,
3922
4081
  displayName: visitorInfoMessage.displayName || visitorInfoMessage.name,
3923
4082
  email: visitorInfoMessage.email,
3924
4083
  isAdmin: this.isAdmin,
3925
- urlAttributes: this.urlAttributes
4084
+ urlAttributes: this.urlAttributes,
3926
4085
  };
3927
4086
  this.attributes = __assign(__assign(__assign({}, visitorInfoMessage.attributes), this.attributes), { currentUrl: window.location.href });
3928
4087
  this.accessToken = visitorInfoMessage.accessToken;
3929
- this.emit("add user");
3930
4088
  this.startSession();
4089
+ this.postVisitorInfo(); // we, the widget, joined the server
3931
4090
  cb();
3932
4091
  };
3933
4092
  StentorRouterChat.prototype.sendChatRating = function () { };
@@ -3939,6 +4098,32 @@ var StentorRouterChat = /** @class */ (function () {
3939
4098
  };
3940
4099
  StentorRouterChat.prototype.flush = function () { };
3941
4100
  StentorRouterChat.prototype.dispose = function () { };
4101
+ StentorRouterChat.prototype.bargeOut = function (_cb) {
4102
+ return __awaiter$1(this, void 0, void 0, function () {
4103
+ return __generator$1(this, function (_a) {
4104
+ this.emit("barge out");
4105
+ return [2 /*return*/];
4106
+ });
4107
+ });
4108
+ };
4109
+ StentorRouterChat.prototype.bargeIn = function (agentName, _cb) {
4110
+ return __awaiter$1(this, void 0, void 0, function () {
4111
+ return __generator$1(this, function (_a) {
4112
+ this.visitorInfo.displayName = agentName;
4113
+ this.emit("barge in");
4114
+ return [2 /*return*/];
4115
+ });
4116
+ });
4117
+ };
4118
+ StentorRouterChat.prototype.postVisitorInfo = function () {
4119
+ return __awaiter$1(this, void 0, void 0, function () {
4120
+ return __generator$1(this, function (_a) {
4121
+ this.sessionCreated = false;
4122
+ this.emit("user joined");
4123
+ return [2 /*return*/];
4124
+ });
4125
+ });
4126
+ };
3942
4127
  StentorRouterChat.prototype.postMessage = function (message) {
3943
4128
  return __awaiter$1(this, void 0, void 0, function () {
3944
4129
  var userId, sessionId, accessToken, attributes, request;
@@ -3947,7 +4132,7 @@ var StentorRouterChat = /** @class */ (function () {
3947
4132
  sessionId = this._sessionId;
3948
4133
  accessToken = this.accessToken;
3949
4134
  attributes = this.attributes || {};
3950
- request = requestFromMessage(message, userId, this.isNewSession, sessionId, accessToken, attributes);
4135
+ request = requestFromMessage(message, userId, this.isNewSession, sessionId, accessToken, attributes, this.visitorInfo);
3951
4136
  this.emit("new message", request);
3952
4137
  return [2 /*return*/];
3953
4138
  });
@@ -3963,34 +4148,61 @@ var StentorRouterChat = /** @class */ (function () {
3963
4148
  else {
3964
4149
  this._userId = "stentor-widget-user-".concat(uuid_1());
3965
4150
  }
3966
- if (get("sessionId") !== "") {
4151
+ var joinSessionId = new URL(window.location.href).searchParams.get("sessionId");
4152
+ if (joinSessionId) {
4153
+ this._sessionId = joinSessionId;
4154
+ set$1("sessionId", this._sessionId);
4155
+ log("Using enforced session id: ".concat(this._sessionId));
4156
+ }
4157
+ else if (get("sessionId")) {
3967
4158
  this._sessionId = get("sessionId");
4159
+ log("Using persisted session id: ".concat(this._sessionId));
3968
4160
  }
3969
4161
  else {
3970
4162
  this._sessionId = "stentor-widget-session-".concat(uuid_1());
3971
4163
  set$1("sessionId", this._sessionId);
4164
+ log("Using generated session id: ".concat(this._sessionId));
3972
4165
  }
3973
- // This is a flag that is cleared after the first message is sent
4166
+ // Always. This triggers a LAUNCH_REQUEST most of the time
3974
4167
  this.isNewSession = true;
4168
+ log("Started session: ".concat(this._sessionId));
3975
4169
  };
3976
- Object.defineProperty(StentorRouterChat.prototype, "userId", {
3977
- get: function () {
3978
- return this._userId;
3979
- },
3980
- enumerable: false,
3981
- configurable: true
3982
- });
3983
- Object.defineProperty(StentorRouterChat.prototype, "sessionId", {
3984
- get: function () {
3985
- return this._sessionId;
3986
- },
3987
- enumerable: false,
3988
- configurable: true
3989
- });
3990
4170
  return StentorRouterChat;
3991
4171
  }());
3992
4172
  function senderToNick(sender) {
3993
- return "".concat(sender.deviceId, "-").concat(sender.userId);
4173
+ // Both are agents
4174
+ return sender.deviceId === "Bot" ?
4175
+ "agent:bot:".concat(sender.userId) : "agent:widget:".concat(sender.userId);
4176
+ }
4177
+ /**
4178
+ *
4179
+ * @param check Function that return true/false if the resource is available
4180
+ * @param stepMs check period in ms
4181
+ * @param timeoutMs max wait in ms
4182
+ * @param resource optional resource name. you will see a log message for every check (step)
4183
+ *
4184
+ * @returns the elapsed time in ms (both resolve/reject)
4185
+ */
4186
+ function waitFor(check, stepMs, timeoutMs, resource) {
4187
+ var elapsedMs = 0;
4188
+ var poll = function (resolve, reject) {
4189
+ if (elapsedMs > timeoutMs) {
4190
+ reject(elapsedMs);
4191
+ }
4192
+ else {
4193
+ if (check()) {
4194
+ resolve(elapsedMs);
4195
+ }
4196
+ else {
4197
+ elapsedMs += stepMs;
4198
+ if (resource) {
4199
+ log("Still waiting for ".concat(resource, " (").concat(elapsedMs, " ms)"));
4200
+ }
4201
+ setTimeout(function (_) { return poll(resolve, reject); }, stepMs);
4202
+ }
4203
+ }
4204
+ };
4205
+ return new Promise(poll);
3994
4206
  }
3995
4207
 
3996
4208
  const PACKET_TYPES = Object.create(null); // no Map = no polyfill
@@ -4042,11 +4254,12 @@ const encodeBlobAsBase64 = (data, callback) => {
4042
4254
  const fileReader = new FileReader();
4043
4255
  fileReader.onload = function () {
4044
4256
  const content = fileReader.result.split(",")[1];
4045
- callback("b" + content);
4257
+ callback("b" + (content || ""));
4046
4258
  };
4047
4259
  return fileReader.readAsDataURL(data);
4048
4260
  };
4049
4261
 
4262
+ // imported from https://github.com/socketio/base64-arraybuffer
4050
4263
  const chars = 'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/';
4051
4264
  // Use a lookup table to find the index.
4052
4265
  const lookup$1 = typeof Uint8Array === 'undefined' ? [] : new Uint8Array(256);
@@ -5214,10 +5427,10 @@ function parse$2(str) {
5214
5427
  }
5215
5428
  function pathNames(obj, path) {
5216
5429
  const regx = /\/{2,9}/g, names = path.replace(regx, "/").split("/");
5217
- if (path.substr(0, 1) == '/' || path.length === 0) {
5430
+ if (path.slice(0, 1) == '/' || path.length === 0) {
5218
5431
  names.splice(0, 1);
5219
5432
  }
5220
- if (path.substr(path.length - 1, 1) == '/') {
5433
+ if (path.slice(-1) == '/') {
5221
5434
  names.splice(names.length - 1, 1);
5222
5435
  }
5223
5436
  return names;
@@ -5310,13 +5523,14 @@ class Socket$1 extends Emitter_1 {
5310
5523
  // Firefox closes the connection when the "beforeunload" event is emitted but not Chrome. This event listener
5311
5524
  // ensures every browser behaves the same (no "disconnect" event at the Socket.IO level when the page is
5312
5525
  // closed/reloaded)
5313
- addEventListener("beforeunload", () => {
5526
+ this.beforeunloadEventListener = () => {
5314
5527
  if (this.transport) {
5315
5528
  // silently close the transport
5316
5529
  this.transport.removeAllListeners();
5317
5530
  this.transport.close();
5318
5531
  }
5319
- }, false);
5532
+ };
5533
+ addEventListener("beforeunload", this.beforeunloadEventListener, false);
5320
5534
  }
5321
5535
  if (this.hostname !== "localhost") {
5322
5536
  this.offlineEventListener = () => {
@@ -5770,6 +5984,7 @@ class Socket$1 extends Emitter_1 {
5770
5984
  // ignore further transport communication
5771
5985
  this.transport.removeAllListeners();
5772
5986
  if (typeof removeEventListener === "function") {
5987
+ removeEventListener("beforeunload", this.beforeunloadEventListener, false);
5773
5988
  removeEventListener("offline", this.offlineEventListener, false);
5774
5989
  }
5775
5990
  // set ready state
@@ -5967,14 +6182,22 @@ function _deconstructPacket(data, buffers) {
5967
6182
  */
5968
6183
  function reconstructPacket(packet, buffers) {
5969
6184
  packet.data = _reconstructPacket(packet.data, buffers);
5970
- packet.attachments = undefined; // no longer useful
6185
+ delete packet.attachments; // no longer useful
5971
6186
  return packet;
5972
6187
  }
5973
6188
  function _reconstructPacket(data, buffers) {
5974
6189
  if (!data)
5975
6190
  return data;
5976
- if (data && data._placeholder) {
5977
- return buffers[data.num]; // appropriate buffer (should be natural order anyway)
6191
+ if (data && data._placeholder === true) {
6192
+ const isIndexValid = typeof data.num === "number" &&
6193
+ data.num >= 0 &&
6194
+ data.num < buffers.length;
6195
+ if (isIndexValid) {
6196
+ return buffers[data.num]; // appropriate buffer (should be natural order anyway)
6197
+ }
6198
+ else {
6199
+ throw new Error("illegal attachments");
6200
+ }
5978
6201
  }
5979
6202
  else if (Array.isArray(data)) {
5980
6203
  for (let i = 0; i < data.length; i++) {
@@ -6028,11 +6251,14 @@ class Encoder {
6028
6251
  encode(obj) {
6029
6252
  if (obj.type === PacketType.EVENT || obj.type === PacketType.ACK) {
6030
6253
  if (hasBinary(obj)) {
6031
- obj.type =
6032
- obj.type === PacketType.EVENT
6254
+ return this.encodeAsBinary({
6255
+ type: obj.type === PacketType.EVENT
6033
6256
  ? PacketType.BINARY_EVENT
6034
- : PacketType.BINARY_ACK;
6035
- return this.encodeAsBinary(obj);
6257
+ : PacketType.BINARY_ACK,
6258
+ nsp: obj.nsp,
6259
+ data: obj.data,
6260
+ id: obj.id,
6261
+ });
6036
6262
  }
6037
6263
  }
6038
6264
  return [this.encodeAsString(obj)];
@@ -6099,9 +6325,13 @@ class Decoder extends Emitter_1 {
6099
6325
  add(obj) {
6100
6326
  let packet;
6101
6327
  if (typeof obj === "string") {
6328
+ if (this.reconstructor) {
6329
+ throw new Error("got plaintext data when reconstructing a packet");
6330
+ }
6102
6331
  packet = this.decodeString(obj);
6103
- if (packet.type === PacketType.BINARY_EVENT ||
6104
- packet.type === PacketType.BINARY_ACK) {
6332
+ const isBinaryEvent = packet.type === PacketType.BINARY_EVENT;
6333
+ if (isBinaryEvent || packet.type === PacketType.BINARY_ACK) {
6334
+ packet.type = isBinaryEvent ? PacketType.EVENT : PacketType.ACK;
6105
6335
  // binary packet's json
6106
6336
  this.reconstructor = new BinaryReconstructor(packet);
6107
6337
  // no attachments, labeled binary but no binary data to follow
@@ -6230,6 +6460,7 @@ class Decoder extends Emitter_1 {
6230
6460
  destroy() {
6231
6461
  if (this.reconstructor) {
6232
6462
  this.reconstructor.finishedReconstruction();
6463
+ this.reconstructor = null;
6233
6464
  }
6234
6465
  }
6235
6466
  }
@@ -7498,6 +7729,20 @@ var StentorServerChat = /** @class */ (function () {
7498
7729
  var _a;
7499
7730
  (_a = this.socket) === null || _a === void 0 ? void 0 : _a.disconnect();
7500
7731
  };
7732
+ StentorServerChat.prototype.bargeOut = function (_cb) {
7733
+ return __awaiter$1(this, void 0, void 0, function () {
7734
+ return __generator$1(this, function (_a) {
7735
+ throw new Error("Method not implemented: bargeOut");
7736
+ });
7737
+ });
7738
+ };
7739
+ StentorServerChat.prototype.bargeIn = function (_agentName, _cb) {
7740
+ return __awaiter$1(this, void 0, void 0, function () {
7741
+ return __generator$1(this, function (_a) {
7742
+ throw new Error("Method not implemented: bargeIn");
7743
+ });
7744
+ });
7745
+ };
7501
7746
  return StentorServerChat;
7502
7747
  }());
7503
7748
 
@@ -8364,6 +8609,8 @@ function useChatServerVisitorId() {
8364
8609
  function useGreeting(active) {
8365
8610
  var curr = useChatServerVisitorId();
8366
8611
  var snapshotRef = React$1.useRef(null);
8612
+ var ctx = React$1.useContext(ChatConfigContext);
8613
+ var isAdmin = ctx.env.isAdmin;
8367
8614
  React$1.useEffect(function () {
8368
8615
  if (active) {
8369
8616
  if (snapshotRef.current !== curr) {
@@ -8376,18 +8623,23 @@ function useGreeting(active) {
8376
8623
  accessToken: curr.accessToken,
8377
8624
  attributes: __assign(__assign({}, curr.attributes), { currentUrl: window.location.href })
8378
8625
  }));
8379
- var timeoutId_1 = setTimeout(function () {
8380
- var greetingAction = sendGreeting();
8381
- curr.dispatch(greetingAction);
8382
- }, 1000);
8383
- return function () {
8384
- clearTimeout(timeoutId_1);
8385
- };
8626
+ if (!isAdmin) {
8627
+ var timeoutId_1 = setTimeout(function () {
8628
+ var greetingAction = sendGreeting();
8629
+ curr.dispatch(greetingAction);
8630
+ }, 1000);
8631
+ return function () {
8632
+ clearTimeout(timeoutId_1);
8633
+ };
8634
+ }
8635
+ else {
8636
+ log("Admin widget. Not sending greeting.");
8637
+ }
8386
8638
  }
8387
8639
  }
8388
8640
  }
8389
8641
  return undefined;
8390
- }, [curr, active]);
8642
+ }, [curr, active, isAdmin]);
8391
8643
  }
8392
8644
 
8393
8645
  function useSuggestionsFetch(search, context) {
@@ -8465,6 +8717,39 @@ function useSuggestions(search, context) {
8465
8717
  }); }, [suggestions, suggestionIndex, execute, suggestionItem]);
8466
8718
  }
8467
8719
 
8720
+ var AdminBar = function (_props) {
8721
+ var name = React$1.useRef(null);
8722
+ // We can manage this locally
8723
+ // const hasAdminJoined = useSelector<ChatState, boolean | undefined>(state => state.hasAdminJoined);
8724
+ var _a = React$1.useState(false), joined = _a[0], setJoined = _a[1];
8725
+ var dispatch = useChatServerDispatch();
8726
+ function onSubmit(event) {
8727
+ var _a;
8728
+ event.preventDefault();
8729
+ if (!joined) {
8730
+ dispatch(sendBargeIn((_a = name.current) === null || _a === void 0 ? void 0 : _a.value));
8731
+ setJoined(true);
8732
+ }
8733
+ else {
8734
+ dispatch(sendBargeOut());
8735
+ setJoined(false);
8736
+ }
8737
+ }
8738
+ function renderJoin() {
8739
+ return (React__default$1["default"].createElement("form", { className: "xappw-admin-input-form", onSubmit: onSubmit },
8740
+ React__default$1["default"].createElement("div", { className: "xappw-admin-input-form__buttons" },
8741
+ React__default$1["default"].createElement(ActionButton, { addClass: "xappw-admin-input-form__btn", type: "submit", label: "Join" })),
8742
+ React__default$1["default"].createElement("div", { className: "xappw-admin-input" },
8743
+ React__default$1["default"].createElement("input", { ref: name, id: "adminBarInput", placeholder: "Type your name here...", className: "xappw-admin-input__input" }))));
8744
+ }
8745
+ function renderLeave() {
8746
+ return (React__default$1["default"].createElement("form", { className: "xappw-admin-input-form", onSubmit: onSubmit },
8747
+ React__default$1["default"].createElement("div", { className: "xappw-admin-input-form__buttons" },
8748
+ React__default$1["default"].createElement(ActionButton, { addClass: "xappw-admin-input-form__btn", type: "submit", label: "Leave" }))));
8749
+ }
8750
+ return (React__default$1["default"].createElement("div", { className: "xappw-admin-input-container visible" }, joined ? renderLeave() : renderJoin()));
8751
+ };
8752
+
8468
8753
  var ChatBranding = function (props) {
8469
8754
  var text = props.text;
8470
8755
  return (React__default$1["default"].createElement("div", { className: "chat-footer__branding" }, text !== null && text !== void 0 ? text : "Powered by XAPP AI"));
@@ -8663,6 +8948,7 @@ var ChatFooter = function (props) {
8663
8948
  React__default$1["default"].createElement("div", { className: "chat-footer__menu-icon" },
8664
8949
  React__default$1["default"].createElement(DrawerBars, { tabIndex: menuButtonTabIndex, onToggle: toggleDrawer }))) : React__default$1["default"].createElement(React__default$1["default"].Fragment, null),
8665
8950
  ((_d = suggestions.suggestions) === null || _d === void 0 ? void 0 : _d.length) > 0 && React__default$1["default"].createElement(Suggestions, { className: "xappw-chat-footer__suggestions", data: suggestions.suggestions, index: suggestions.index, onItemClick: handleItemClick, onItemUse: handleItemUse }),
8951
+ props.isAdmin && props.isChatting && props.visible && React__default$1["default"].createElement(AdminBar, null),
8666
8952
  React__default$1["default"].createElement(Input, { addClass: "chat-footer__input " + (props.isChatting && props.visible ? "visible" : ""), suggestion: suggestions.item, value: input, placeholder: placeholder, sendButtonIcon: sendButtonIcon, footerConfig: footerConfig, inputConfig: inputConfig, onSubmit: handleSubmit, onChange: handleChange, onSuggestionCommand: suggestions.execute,
8667
8953
  // onFocus={this.inputOnFocus}
8668
8954
  onFileUpload: props.onFileUpload }),
@@ -31070,15 +31356,15 @@ var TypingIndicator = function (_) {
31070
31356
  * Show the agent is typing (or the bot - for fun)
31071
31357
  */
31072
31358
  var TypingStatus = function (props) {
31073
- var agent_names = Object.values(props.agents).filter(function (agent) { return agent.typing; });
31074
- return (React__default$1["default"].createElement(React__default$1["default"].Fragment, null, agent_names.map(function (agent) {
31359
+ var agentsTyping = Object.values(props.agents).filter(function (agent) { return agent.typing; });
31360
+ return (React__default$1["default"].createElement(React__default$1["default"].Fragment, null, agentsTyping.map(function (agent) {
31075
31361
  var _a, _b;
31076
31362
  return (React__default$1["default"].createElement(React__default$1["default"].Fragment, null, !props.textTypingStatusEnabled ? (React__default$1["default"].createElement("div", { className: "chat-msg-container-wrapper", key: "typing-status-".concat(agent.user.nick) },
31077
31363
  React__default$1["default"].createElement("div", { key: agent.user.nick, className: "chat-msg-container agent chat-typing-progress" },
31078
31364
  React__default$1["default"].createElement(ChatMessagePart, { user: agent.user, showAvatar: true },
31079
31365
  React__default$1["default"].createElement("div", { className: "chat-msg" },
31080
31366
  React__default$1["default"].createElement(ChatMessageBubble, { owner: "others", hasTail: true },
31081
- React__default$1["default"].createElement(TypingIndicator, null))))))) : (React__default$1["default"].createElement("div", { key: "typing-status-".concat(agent.user.nick), className: "chat-msg-agent-typing" }, (_b = (_a = agent.user) === null || _a === void 0 ? void 0 : _a.displayName) !== null && _b !== void 0 ? _b : "Bot",
31367
+ React__default$1["default"].createElement(TypingIndicator, null))))))) : (React__default$1["default"].createElement("div", { key: "typing-status-".concat(agent.user.nick), className: "chat-msg-agent-typing" }, (_b = (_a = agent.user) === null || _a === void 0 ? void 0 : _a.displayName) !== null && _b !== void 0 ? _b : "Somebody",
31082
31368
  " is typing"))));
31083
31369
  })));
31084
31370
  };
@@ -31127,9 +31413,18 @@ var MessageList = function (props) {
31127
31413
  */
31128
31414
  function renderByType(msg, sibling) {
31129
31415
  var _a;
31130
- var user = ((_a = props.agents[msg.user.nick]) === null || _a === void 0 ? void 0 : _a.user) || props.agent;
31131
- if (!user) {
31132
- console.warn("Could not get a user from agents list from ".concat(msg.user.nick, " or has an "));
31416
+ var user;
31417
+ // visitor is this widget
31418
+ if (msg.user.nick.startsWith("visitor:")) {
31419
+ user = msg.user;
31420
+ }
31421
+ else {
31422
+ user = ((_a = props.agents[msg.user.nick]) === null || _a === void 0 ? void 0 : _a.user) || props.agent;
31423
+ // Still nothing?
31424
+ if (!user) {
31425
+ console.warn("Could not get a user from agents list with nick: \"".concat(msg.user.nick, "\""));
31426
+ user = msg.user;
31427
+ }
31133
31428
  }
31134
31429
  switch (msg.type) {
31135
31430
  case "chat.file":
@@ -31731,8 +32026,8 @@ var ChatWidget = function (props) {
31731
32026
  });
31732
32027
  }
31733
32028
  }
31734
- useGreeting(!isOffline && !props.preChatFormEnabled && visible);
31735
32029
  var config = props.config, onConnectionStatusChange = props.onConnectionStatusChange;
32030
+ useGreeting(!isOffline && !props.preChatFormEnabled && visible);
31736
32031
  var connectionStatus = chatState.connection.connectionStatus;
31737
32032
  React$1.useEffect(function () {
31738
32033
  if (onConnectionStatusChange) {
@@ -31748,7 +32043,7 @@ var ChatWidget = function (props) {
31748
32043
  React__default$1["default"].createElement("div", { className: "spinner-container ".concat(visible && connectionStatus === "pending" ? "visible" : "") },
31749
32044
  React__default$1["default"].createElement("div", { className: "spinner" })),
31750
32045
  connectionStatus === "offline" && React__default$1["default"].createElement(ServerOffline, null),
31751
- React__default$1["default"].createElement(ChatFooter, { isChatting: chatState.isChatting, placeholder: (_r = config === null || config === void 0 ? void 0 : config.input) === null || _r === void 0 ? void 0 : _r.placeholder, sendButtonIcon: (_t = (_s = config === null || config === void 0 ? void 0 : config.footer) === null || _s === void 0 ? void 0 : _s.sendButton) === null || _t === void 0 ? void 0 : _t.icon, visible: visible, menuConfig: props.config.menu, footerConfig: (_u = props.config) === null || _u === void 0 ? void 0 : _u.footer, inputConfig: (_v = props.config) === null || _v === void 0 ? void 0 : _v.input, onChange: handleOnChange, onSubmit: handleOnSubmit, onFileUpload: handleFileUpload }),
32046
+ React__default$1["default"].createElement(ChatFooter, { isAdmin: config === null || config === void 0 ? void 0 : config.isAdmin, isChatting: chatState.isChatting, placeholder: (_r = config === null || config === void 0 ? void 0 : config.input) === null || _r === void 0 ? void 0 : _r.placeholder, sendButtonIcon: (_t = (_s = config === null || config === void 0 ? void 0 : config.footer) === null || _s === void 0 ? void 0 : _s.sendButton) === null || _t === void 0 ? void 0 : _t.icon, visible: visible, menuConfig: props.config.menu, footerConfig: (_u = props.config) === null || _u === void 0 ? void 0 : _u.footer, inputConfig: (_v = props.config) === null || _v === void 0 ? void 0 : _v.input, onChange: handleOnChange, onSubmit: handleOnSubmit, onFileUpload: handleFileUpload }),
31752
32047
  React__default$1["default"].createElement("div", { className: "restartModal", ref: modalRef, onClick: closeModal },
31753
32048
  React__default$1["default"].createElement(ModalContent, { onClose: closeModal, onReset: refreshOnClick }))),
31754
32049
  React__default$1["default"].createElement(ChatButton, { addClass: getVisibilityClass(), onClick: chatButtonOnClick, config: (_w = props.config) === null || _w === void 0 ? void 0 : _w.cta, visible: visible })));
@@ -31866,7 +32161,6 @@ function persistStateReducer(storage, initialState, innerReducer) {
31866
32161
  }
31867
32162
 
31868
32163
  function connectionReducer(state, action) {
31869
- log("action", action);
31870
32164
  switch (action.type) {
31871
32165
  case "connection_update":
31872
32166
  return __assign(__assign({}, state), { connectionStatus: action.detail.status });
@@ -31883,31 +32177,32 @@ function joinMessages(messages, msg) {
31883
32177
  }
31884
32178
 
31885
32179
  function memberJoin(state, detail) {
31886
- var _a;
31887
32180
  if (state.chats.length === 0) {
31888
32181
  set$1("sessionId", "");
31889
32182
  }
32183
+ var agents = __assign({}, state.agents);
32184
+ var prevAgentInfo = state.agents[detail.user.nick];
32185
+ agents[detail.user.nick] = __assign(__assign({}, prevAgentInfo), { user: __assign(__assign({}, detail.user), { displayName: detail.user.displayName || "Agent" }), joined: true, typing: false });
31890
32186
  if (isAgent(detail.user.nick)) {
31891
- var prevAgentInfo = state.agents[detail.user.nick];
31892
- return __assign(__assign({}, state), { isChatting: true, chats: (prevAgentInfo === null || prevAgentInfo === void 0 ? void 0 : prevAgentInfo.joined) ? state.chats : joinMessages(state.chats, detail), agents: (_a = {},
31893
- _a[detail.user.nick] = __assign(__assign({}, prevAgentInfo), { user: __assign(__assign({}, detail.user), { displayName: detail.user.displayName || "Bot" }), joined: true, typing: false }),
31894
- _a) });
32187
+ return __assign(__assign({}, state), { isChatting: true, chats: (prevAgentInfo === null || prevAgentInfo === void 0 ? void 0 : prevAgentInfo.joined) ? state.chats : joinMessages(state.chats, detail), agents: agents });
31895
32188
  }
31896
32189
  else {
31897
- return __assign(__assign({}, state), { isChatting: true, chats: joinMessages(state.chats, detail) });
32190
+ return __assign(__assign({}, state), { isChatting: true, chats: joinMessages(state.chats, detail), agents: agents });
31898
32191
  }
31899
32192
  }
31900
32193
 
31901
32194
  function memberLeave(state, detail) {
31902
- var _a;
32195
+ var agents = __assign({}, state.agents);
32196
+ var prevAgentInfo = state.agents[detail.user.nick];
32197
+ agents[detail.user.nick] = __assign(__assign({}, prevAgentInfo), { joined: false, typing: false });
32198
+ // count number of agents that are still joined
32199
+ var agentsJoined = Object.values(agents).filter(function (agent) { return agent.joined; });
32200
+ var isChatting = agentsJoined.length > 0;
31903
32201
  if (isAgent(detail.user.nick)) {
31904
- var prevAgentInfo = state.agents[detail.user.nick];
31905
- return __assign(__assign({}, state), { isChatting: false, chats: (prevAgentInfo === null || prevAgentInfo === void 0 ? void 0 : prevAgentInfo.joined) ? joinMessages(state.chats, detail) : state.chats, agents: (_a = {},
31906
- _a[detail.user.nick] = __assign(__assign({}, prevAgentInfo), { joined: false }),
31907
- _a) });
32202
+ return __assign(__assign({}, state), { isChatting: isChatting, chats: (prevAgentInfo === null || prevAgentInfo === void 0 ? void 0 : prevAgentInfo.joined) ? joinMessages(state.chats, detail) : state.chats, agents: agents });
31908
32203
  }
31909
32204
  else {
31910
- return __assign(__assign({}, state), { isChatting: false, chats: joinMessages(state.chats, detail) });
32205
+ return __assign(__assign({}, state), { isChatting: isChatting, chats: joinMessages(state.chats, detail), agents: agents });
31911
32206
  }
31912
32207
  }
31913
32208
 
@@ -31937,15 +32232,19 @@ function update(state, action) {
31937
32232
  if (action.type === "reset") {
31938
32233
  return resetReducer(state);
31939
32234
  }
31940
- // workaround until state is split. Use combineReducers afterwards
31941
- var newConnectionState = connectionReducer(state.connection, action);
31942
- if (state.connection !== newConnectionState) {
31943
- state = __assign(__assign({}, state), { connection: newConnectionState });
31944
- }
31945
32235
  if (action.detail) {
31946
32236
  state.lastTimestamp = action.detail.timestamp;
31947
32237
  }
31948
32238
  switch (action.type) {
32239
+ case "connection_update":
32240
+ case "receiveToken":
32241
+ case "sendGreeting":
32242
+ // workaround until state is split. Use combineReducers afterwards
32243
+ var newConnectionState = connectionReducer(state.connection, action);
32244
+ if (state.connection !== newConnectionState) {
32245
+ state = __assign(__assign({}, state), { connection: newConnectionState });
32246
+ }
32247
+ return state;
31949
32248
  case "account_status":
31950
32249
  return __assign(__assign({}, state), { accountStatus: action.detail.status });
31951
32250
  case "department_update":