@xapp/chat-widget 1.53.1 → 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.es.js CHANGED
@@ -2023,12 +2023,20 @@ function executeAction(text, token) {
2023
2023
  }; };
2024
2024
  }
2025
2025
 
2026
+ /**
2027
+ * This is not used anymore. It was part of the handshake with the legacy "chat server"
2028
+ *
2029
+ * @param token
2030
+ * @returns
2031
+ */
2026
2032
  function receiveToken(token) {
2027
2033
  return {
2028
2034
  type: "receiveToken",
2029
2035
  detail: {
2030
2036
  token: token,
2031
- timestamp: +Date()
2037
+ timestamp: +Date(),
2038
+ type: "receiveToken",
2039
+ user: undefined
2032
2040
  }
2033
2041
  };
2034
2042
  }
@@ -2147,6 +2155,26 @@ function setConnectionStatus(status) {
2147
2155
  };
2148
2156
  }
2149
2157
 
2158
+ function sendBargeIn(agentName) {
2159
+ return function (chatServer) { return function () {
2160
+ chatServer.bargeIn(agentName, function (err) {
2161
+ if (err) {
2162
+ log(err);
2163
+ }
2164
+ });
2165
+ }; };
2166
+ }
2167
+
2168
+ function sendBargeOut() {
2169
+ return function (chatServer) { return function () {
2170
+ chatServer.bargeOut(function (err) {
2171
+ if (err) {
2172
+ log(err);
2173
+ }
2174
+ });
2175
+ }; };
2176
+ }
2177
+
2150
2178
  function reset() {
2151
2179
  return {
2152
2180
  type: "reset"
@@ -2161,6 +2189,14 @@ var LogChat = /** @class */ (function () {
2161
2189
  function LogChat(inner) {
2162
2190
  this.inner = inner;
2163
2191
  }
2192
+ LogChat.prototype.bargeOut = function (cb) {
2193
+ log("CLIENT: bargeOut");
2194
+ this.inner.bargeOut(cb);
2195
+ };
2196
+ LogChat.prototype.bargeIn = function (agentName, cb) {
2197
+ log("CLIENT: bargeIn: ".concat(agentName));
2198
+ this.inner.bargeIn(agentName, cb);
2199
+ };
2164
2200
  LogChat.prototype.init = function (dispatch) {
2165
2201
  this.inner.init(dispatch);
2166
2202
  };
@@ -2631,7 +2667,7 @@ function parseSuggestionsResponse(response, direction) {
2631
2667
  }, []);
2632
2668
  }
2633
2669
 
2634
- /*! *****************************************************************************
2670
+ /******************************************************************************
2635
2671
  Copyright (c) Microsoft Corporation.
2636
2672
 
2637
2673
  Permission to use, copy, modify, and/or distribute this software for any
@@ -2662,7 +2698,7 @@ function __generator(thisArg, body) {
2662
2698
  function verb(n) { return function (v) { return step([n, v]); }; }
2663
2699
  function step(op) {
2664
2700
  if (f) throw new TypeError("Generator is already executing.");
2665
- while (_) try {
2701
+ while (g && (g = 0, op[0] && (_ = 0)), _) try {
2666
2702
  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;
2667
2703
  if (y = 0, t) op = [op[0] & 2, t.value];
2668
2704
  switch (op[0]) {
@@ -3233,6 +3269,20 @@ var StentorDirectChat = /** @class */ (function () {
3233
3269
  });
3234
3270
  });
3235
3271
  };
3272
+ StentorDirectChat.prototype.bargeOut = function (_cb) {
3273
+ return __awaiter$1(this, void 0, void 0, function () {
3274
+ return __generator$1(this, function (_a) {
3275
+ throw new Error("Method not implemented: bargeOut");
3276
+ });
3277
+ });
3278
+ };
3279
+ StentorDirectChat.prototype.bargeIn = function (_agentName, _cb) {
3280
+ return __awaiter$1(this, void 0, void 0, function () {
3281
+ return __generator$1(this, function (_a) {
3282
+ throw new Error("Method not implemented: bargeIn");
3283
+ });
3284
+ });
3285
+ };
3236
3286
  StentorDirectChat.prototype.getBot = function (user) {
3237
3287
  var _a;
3238
3288
  var bot = (_a = this.options) === null || _a === void 0 ? void 0 : _a.bot;
@@ -3552,12 +3602,16 @@ var StentorLocalChat = /** @class */ (function () {
3552
3602
  };
3553
3603
  StentorLocalChat.prototype.dispose = function () {
3554
3604
  };
3605
+ StentorLocalChat.prototype.bargeOut = function () {
3606
+ };
3607
+ StentorLocalChat.prototype.bargeIn = function () {
3608
+ };
3555
3609
  return StentorLocalChat;
3556
3610
  }());
3557
3611
 
3558
3612
  /*! Copyright (c) 2022, XAPPmedia */
3559
3613
  var PERMISSION_QUESTION_EXPIRATION_MS = 300000; // 5 minutes
3560
- function requestFromMessage(message, userId, isNewSession, sessionId, accessToken, attributes) {
3614
+ function requestFromMessage(message, userId, isNewSession, sessionId, accessToken, attributes, visitorInfo) {
3561
3615
  var _a, _b, _c, _d;
3562
3616
  var request;
3563
3617
  var now = new Date().getTime();
@@ -3583,13 +3637,13 @@ function requestFromMessage(message, userId, isNewSession, sessionId, accessToke
3583
3637
  var expired = now - permissionRequest.time > PERMISSION_QUESTION_EXPIRATION_MS;
3584
3638
  var text = (_d = message.msg.text) === null || _d === void 0 ? void 0 : _d.toLowerCase();
3585
3639
  var granted = !expired;
3586
- var userProfile = { id: this._userId };
3640
+ var userProfile = { id: userId };
3587
3641
  if (!expired) {
3588
3642
  if (permissionRequest.type === "EMAIL") {
3589
3643
  var isEmail = looksLikeEmail(text);
3590
3644
  granted = isEmail;
3591
- userProfile.email = this.visitorInfo.email;
3592
- userProfile.name = this.visitorInfo.displayName;
3645
+ userProfile.email = visitorInfo.email;
3646
+ userProfile.name = visitorInfo.displayName;
3593
3647
  this.visitorInfo.email = text;
3594
3648
  }
3595
3649
  if (permissionRequest.type === "LOCATION_PRECISE") {
@@ -3605,8 +3659,8 @@ function requestFromMessage(message, userId, isNewSession, sessionId, accessToke
3605
3659
  request = {
3606
3660
  type: "PERMISSION_GRANT",
3607
3661
  rawQuery: message.msg.text,
3608
- sessionId: this._sessionId,
3609
- userId: this._userId,
3662
+ sessionId: sessionId,
3663
+ userId: userId,
3610
3664
  isNewSession: false,
3611
3665
  granted: granted,
3612
3666
  userProfile: userProfile,
@@ -3614,13 +3668,13 @@ function requestFromMessage(message, userId, isNewSession, sessionId, accessToke
3614
3668
  platform: "stentor-platform",
3615
3669
  channel: "widget",
3616
3670
  accessToken: accessToken,
3617
- attributes: attributes
3671
+ attributes: attributes,
3618
3672
  };
3619
3673
  }
3620
3674
  else if (message.type === "custom") {
3621
3675
  request = __assign(__assign({}, JSON.parse(message.payload)), {
3622
3676
  // token: message.msg.token,
3623
- sessionId: this._sessionId, userId: this._userId, isNewSession: false,
3677
+ sessionId: sessionId, userId: userId, isNewSession: false,
3624
3678
  // intentId: "OptionSelect",
3625
3679
  platform: "stentor-platform", channel: "widget", accessToken: accessToken, attributes: attributes });
3626
3680
  }
@@ -3628,28 +3682,28 @@ function requestFromMessage(message, userId, isNewSession, sessionId, accessToke
3628
3682
  request = {
3629
3683
  type: "OPTION_SELECT_REQUEST",
3630
3684
  token: message.msg.token,
3631
- sessionId: this._sessionId,
3632
- userId: this._userId,
3685
+ sessionId: sessionId,
3686
+ userId: userId,
3633
3687
  isNewSession: false,
3634
3688
  intentId: "OptionSelect",
3635
3689
  platform: "stentor-platform",
3636
3690
  channel: "widget",
3637
3691
  accessToken: accessToken,
3638
- attributes: attributes
3692
+ attributes: attributes,
3639
3693
  };
3640
3694
  }
3641
3695
  else {
3642
3696
  request = {
3643
3697
  type: "INTENT_REQUEST",
3644
3698
  rawQuery: message.msg.text,
3645
- sessionId: this._sessionId,
3646
- userId: this._userId,
3699
+ sessionId: sessionId,
3700
+ userId: userId,
3647
3701
  isNewSession: false,
3648
3702
  intentId: "NLU_RESULT_PLACEHOLDER",
3649
3703
  platform: "stentor-platform",
3650
3704
  channel: "widget",
3651
3705
  accessToken: accessToken,
3652
- attributes: attributes
3706
+ attributes: attributes,
3653
3707
  };
3654
3708
  }
3655
3709
  }
@@ -3699,29 +3753,37 @@ var StentorRouterChat = /** @class */ (function () {
3699
3753
  this.handlers = {};
3700
3754
  this.config = config;
3701
3755
  this.options = options;
3702
- // Dig out the path parameters. Put them into the attributes.
3756
+ // Dig out the path parameters. Put them into the attributes.
3703
3757
  // The WS url is the barebone domain.
3704
3758
  var url = new URL(this.config.url);
3705
3759
  var urlPath = (_a = url.pathname) === null || _a === void 0 ? void 0 : _a.split("/");
3706
- // eslint-disable-next-line @typescript-eslint/no-explicit-any
3707
- this.isAdmin = (url.searchParams.get('isAdmin') || window.xaIsAdmin) === "true";
3760
+ var locationUrl = new URL(window.location.href);
3761
+ this.isAdmin = locationUrl.searchParams.get("isAdmin") === "true";
3708
3762
  this.serverUrl = "".concat(url.origin);
3709
3763
  if (urlPath && urlPath.length > 1) {
3710
3764
  this.serverUrl = "".concat(this.serverUrl, "/").concat(urlPath[1]); // the first path (after the initial "") is the "dev" or "prod"
3711
- this.urlAttributes.path = urlPath.slice(2);
3765
+ this.urlAttributes.path = urlPath.slice(1);
3712
3766
  }
3713
- log("WS url: ".concat(this.serverUrl, " attributes: ").concat(JSON.stringify(this.attributes)));
3714
- // this.configurableMessages = options.configurableMessages;
3767
+ log("WS url: ".concat(this.serverUrl, " isAdmin: ").concat(this.isAdmin, " attributes: ").concat(JSON.stringify(this.attributes)));
3768
+ this.configurableMessages = getConfigurableMessagesConfig(options.configurableMessages);
3715
3769
  }
3716
3770
  StentorRouterChat.prototype.init = function (dispatch) {
3717
3771
  var _this = this;
3718
- // Fire up the WebSocket
3719
- this.autoReconnect(this.wsCreate.bind(this));
3720
3772
  this.dispatch = dispatch;
3773
+ this.setAccountStatus("offline");
3721
3774
  // Register "handlers" for the incoming events
3722
- this.handlers["account_status"] = function (_data, _sender) {
3723
- // Register the "endpoint" with the server (send visitor data)
3724
- _this.emit("connection update");
3775
+ this.handlers["connection update"] = function (data, _sender) {
3776
+ log("Connection update received. Session created: ".concat(data.sessionCreated, " Error: ").concat(data.errorMessage || ""));
3777
+ if (data.sessionCreated) {
3778
+ _this.sessionCreated = true;
3779
+ }
3780
+ else {
3781
+ // Shut down
3782
+ _this.dispatch(setAccountStatus("offline"));
3783
+ _this.dispatch(setConnectionStatus("offline"));
3784
+ }
3785
+ };
3786
+ this.handlers["account status"] = function (_data, _sender) {
3725
3787
  dispatch({
3726
3788
  type: "account_status",
3727
3789
  detail: {
@@ -3730,6 +3792,11 @@ var StentorRouterChat = /** @class */ (function () {
3730
3792
  },
3731
3793
  });
3732
3794
  };
3795
+ this.handlers["failure"] = function (data, sender) {
3796
+ err("Router says something failed: type: ".concat(data.type, " tries: ").concat(data.tries, " error: ").concat(data.error));
3797
+ var _a = _this.configurableMessages[data.tries], retry = _a.retry, delay = _a.delay, text = _a.text;
3798
+ _this.sendFailureMessage(retry, data.delay || delay, text, sender);
3799
+ };
3733
3800
  this.handlers["new message"] = function (data, sender) {
3734
3801
  // Because the router's internal message format is Stentor channel compatible.
3735
3802
  // So the data is either a stentor Request (from widget) or a stentor Response (from bot)
@@ -3755,7 +3822,7 @@ var StentorRouterChat = /** @class */ (function () {
3755
3822
  displayName: sender.displayName || sender.email || sender.userId,
3756
3823
  nick: senderToNick(sender),
3757
3824
  },
3758
- msg: message,
3825
+ msg: message.msg,
3759
3826
  timestamp: +new Date(),
3760
3827
  },
3761
3828
  });
@@ -3821,27 +3888,30 @@ var StentorRouterChat = /** @class */ (function () {
3821
3888
  _this.dispatch(setAccountStatus("online"));
3822
3889
  _this.dispatch(setConnectionStatus("online"));
3823
3890
  };
3824
- this.handlers["reconnect_failed"] = function (_data) {
3891
+ this.handlers["reconnect failed"] = function (_data) {
3825
3892
  _this.dispatch(setAccountStatus("offline"));
3826
3893
  _this.dispatch(setConnectionStatus("offline"));
3827
3894
  };
3828
- this.handlers["reconnect_error"] = function (_data) {
3895
+ this.handlers["reconnect error"] = function (_data) {
3829
3896
  _this.dispatch(setAccountStatus("offline"));
3830
3897
  };
3831
- this.setAccountStatus("offline");
3898
+ // pretend we are online. The emit() will connect
3899
+ this.setAccountStatus("online");
3900
+ this.setConnectionStatus("online");
3832
3901
  };
3833
3902
  StentorRouterChat.prototype.autoReconnect = function (wsCreate) {
3834
3903
  var _this = this;
3835
- var setStatus = this.setAccountStatus.bind(this);
3904
+ var setActStatus = this.setAccountStatus.bind(this);
3905
+ var setConnStatus = this.setConnectionStatus.bind(this);
3836
3906
  function startReconnecting() {
3837
- setStatus("offline");
3838
3907
  var interval = setInterval(function () {
3839
3908
  log("Re-creating WS connection");
3840
3909
  var ws = wsCreate();
3841
3910
  ws.onopen = function () {
3842
3911
  log("Re-opened WS connection");
3843
3912
  // We are connected
3844
- setStatus("online");
3913
+ setActStatus("online");
3914
+ setConnStatus("online");
3845
3915
  ws.onclose = startReconnecting;
3846
3916
  clearInterval(interval);
3847
3917
  };
@@ -3854,26 +3924,77 @@ var StentorRouterChat = /** @class */ (function () {
3854
3924
  log("Opened WS connection");
3855
3925
  // We are connected
3856
3926
  _this.setAccountStatus("online");
3927
+ _this.setConnectionStatus("online");
3857
3928
  };
3858
3929
  };
3859
3930
  StentorRouterChat.prototype.wsCreate = function () {
3860
- this.ws = new WebSocket("".concat(this.serverUrl, "?userId=").concat(this._userId));
3861
- this.ws.onmessage = function (data) {
3862
- console.log("SERVER says: ".concat(JSON.stringify(data)));
3863
- // const message: RouterMessage = JSON.parse(data);
3864
- // this.handlers[message.event](message.data, message.sender);
3931
+ var _this = this;
3932
+ this.setConnectionStatus("pending");
3933
+ this.ws = new WebSocket("".concat(this.serverUrl, "?userId=").concat(this._userId, "&isAdmin=").concat(this.isAdmin));
3934
+ this.ws.onerror = function (ev) {
3935
+ var _a;
3936
+ log("Error in WS connection. Type: ".concat(!ev ? "?" : ev.type, " Ready State: ").concat((_a = _this.ws) === null || _a === void 0 ? void 0 : _a.readyState));
3937
+ _this.setConnectionStatus("pending");
3938
+ };
3939
+ this.ws.onmessage = function (me) {
3940
+ log("ROUTER says: ".concat(me.data));
3941
+ var message = JSON.parse(me.data);
3942
+ var handler = _this.handlers[message.event];
3943
+ if (handler) {
3944
+ _this.handlers[message.event](message.data, message.sender);
3945
+ }
3946
+ else {
3947
+ log("Unknown router message event: ".concat(message.event));
3948
+ }
3865
3949
  };
3866
3950
  return this.ws;
3867
3951
  };
3952
+ StentorRouterChat.prototype.checkConnection = function () {
3953
+ return this.ws.readyState === WebSocket.OPEN;
3954
+ };
3868
3955
  StentorRouterChat.prototype.emit = function (event, data) {
3869
- var payloadData = JSON.stringify({ event: event, data: data, sender: this.visitorInfo });
3870
- log("Widget says: ".concat(payloadData));
3871
- this.ws.send(payloadData);
3956
+ return __awaiter$1(this, void 0, void 0, function () {
3957
+ var payloadData;
3958
+ var _this = this;
3959
+ return __generator$1(this, function (_a) {
3960
+ switch (_a.label) {
3961
+ case 0:
3962
+ payloadData = JSON.stringify({
3963
+ event: event,
3964
+ data: data,
3965
+ sender: this.visitorInfo,
3966
+ sessionId: this._sessionId,
3967
+ });
3968
+ log("Widget says: ".concat(payloadData));
3969
+ if (!this.ws) {
3970
+ // Fire up the WebSocket
3971
+ this.autoReconnect(this.wsCreate.bind(this));
3972
+ }
3973
+ return [4 /*yield*/, waitFor(this.checkConnection.bind(this), 500, 5000, "connection")
3974
+ .then(function (t) {
3975
+ if (t > 0) {
3976
+ log("Connection is ready in ".concat(t, " ms"));
3977
+ }
3978
+ _this.ws.send(payloadData);
3979
+ })
3980
+ .catch(function (t) {
3981
+ console.log("Connection wait timed out in ".concat(t, " ms"));
3982
+ })];
3983
+ case 1:
3984
+ _a.sent();
3985
+ return [2 /*return*/];
3986
+ }
3987
+ });
3988
+ });
3872
3989
  };
3873
3990
  StentorRouterChat.prototype.setAccountStatus = function (status) {
3874
3991
  log("SERVER account_status: ".concat(JSON.stringify(status)));
3875
3992
  this.dispatch(setAccountStatus(status));
3876
3993
  };
3994
+ StentorRouterChat.prototype.setConnectionStatus = function (status) {
3995
+ log("SERVER: connection_update: ".concat(JSON.stringify(status)));
3996
+ this.dispatch(setConnectionStatus(status));
3997
+ };
3877
3998
  StentorRouterChat.prototype.sendOfflineMsg = function (_, cb) {
3878
3999
  cb();
3879
4000
  };
@@ -3890,11 +4011,48 @@ var StentorRouterChat = /** @class */ (function () {
3890
4011
  });
3891
4012
  });
3892
4013
  };
4014
+ StentorRouterChat.prototype.sendFailureMessage = function (retry, delay, text, sender) {
4015
+ this.dispatch({
4016
+ type: "chat",
4017
+ detail: {
4018
+ type: "chat.typing",
4019
+ user: {
4020
+ nick: senderToNick(sender),
4021
+ },
4022
+ typing: false,
4023
+ timestamp: +new Date(),
4024
+ },
4025
+ });
4026
+ this.dispatch({
4027
+ type: "chat",
4028
+ detail: {
4029
+ type: "chat.failureMsg",
4030
+ user: {
4031
+ nick: senderToNick(sender)
4032
+ },
4033
+ failureMsg: { retry: retry, delay: delay, text: text },
4034
+ timestamp: +new Date()
4035
+ }
4036
+ });
4037
+ };
4038
+ StentorRouterChat.prototype.checkSession = function () {
4039
+ return this.sessionCreated;
4040
+ };
3893
4041
  StentorRouterChat.prototype.sendChatMsgRequest = function (serviceRequest, cb) {
3894
4042
  return __awaiter$1(this, void 0, void 0, function () {
4043
+ var _this = this;
3895
4044
  return __generator$1(this, function (_a) {
3896
4045
  switch (_a.label) {
3897
- case 0: return [4 /*yield*/, this.postMessage(serviceRequest)];
4046
+ case 0: return [4 /*yield*/, waitFor(this.checkSession.bind(this), 500, 5000, "session creation")
4047
+ .then(function (t) {
4048
+ if (t > 0) {
4049
+ log("Session creation is ready in ".concat(t, " ms"));
4050
+ }
4051
+ _this.postMessage(serviceRequest);
4052
+ })
4053
+ .catch(function (t) {
4054
+ console.log("Session creation wait timed out in ".concat(t, " ms"));
4055
+ })];
3898
4056
  case 1:
3899
4057
  _a.sent();
3900
4058
  cb();
@@ -3903,23 +4061,24 @@ var StentorRouterChat = /** @class */ (function () {
3903
4061
  });
3904
4062
  });
3905
4063
  };
3906
- StentorRouterChat.prototype.sendTyping = function (isTyping) {
3907
- this.emit(isTyping ? "typing" : "stop typing");
4064
+ StentorRouterChat.prototype.sendTyping = function (_isTyping) {
4065
+ // TODO: Is this too much traffic?
4066
+ // this.emit(isTyping ? "typing" : "stop typing");
3908
4067
  };
3909
4068
  StentorRouterChat.prototype.setVisitorInfo = function (visitorInfoMessage, cb) {
3910
- log("Visitor Info Mesage = ".concat(visitorInfoMessage));
4069
+ log("Visitor Info Message = ".concat(JSON.stringify(visitorInfoMessage)));
3911
4070
  this.visitorInfo = {
3912
4071
  deviceId: "Widget",
3913
4072
  userId: visitorInfoMessage.userId,
3914
4073
  displayName: visitorInfoMessage.displayName || visitorInfoMessage.name,
3915
4074
  email: visitorInfoMessage.email,
3916
4075
  isAdmin: this.isAdmin,
3917
- urlAttributes: this.urlAttributes
4076
+ urlAttributes: this.urlAttributes,
3918
4077
  };
3919
4078
  this.attributes = __assign(__assign(__assign({}, visitorInfoMessage.attributes), this.attributes), { currentUrl: window.location.href });
3920
4079
  this.accessToken = visitorInfoMessage.accessToken;
3921
- this.emit("add user");
3922
4080
  this.startSession();
4081
+ this.postVisitorInfo(); // we, the widget, joined the server
3923
4082
  cb();
3924
4083
  };
3925
4084
  StentorRouterChat.prototype.sendChatRating = function () { };
@@ -3931,6 +4090,32 @@ var StentorRouterChat = /** @class */ (function () {
3931
4090
  };
3932
4091
  StentorRouterChat.prototype.flush = function () { };
3933
4092
  StentorRouterChat.prototype.dispose = function () { };
4093
+ StentorRouterChat.prototype.bargeOut = function (_cb) {
4094
+ return __awaiter$1(this, void 0, void 0, function () {
4095
+ return __generator$1(this, function (_a) {
4096
+ this.emit("barge out");
4097
+ return [2 /*return*/];
4098
+ });
4099
+ });
4100
+ };
4101
+ StentorRouterChat.prototype.bargeIn = function (agentName, _cb) {
4102
+ return __awaiter$1(this, void 0, void 0, function () {
4103
+ return __generator$1(this, function (_a) {
4104
+ this.visitorInfo.displayName = agentName;
4105
+ this.emit("barge in");
4106
+ return [2 /*return*/];
4107
+ });
4108
+ });
4109
+ };
4110
+ StentorRouterChat.prototype.postVisitorInfo = function () {
4111
+ return __awaiter$1(this, void 0, void 0, function () {
4112
+ return __generator$1(this, function (_a) {
4113
+ this.sessionCreated = false;
4114
+ this.emit("user joined");
4115
+ return [2 /*return*/];
4116
+ });
4117
+ });
4118
+ };
3934
4119
  StentorRouterChat.prototype.postMessage = function (message) {
3935
4120
  return __awaiter$1(this, void 0, void 0, function () {
3936
4121
  var userId, sessionId, accessToken, attributes, request;
@@ -3939,7 +4124,7 @@ var StentorRouterChat = /** @class */ (function () {
3939
4124
  sessionId = this._sessionId;
3940
4125
  accessToken = this.accessToken;
3941
4126
  attributes = this.attributes || {};
3942
- request = requestFromMessage(message, userId, this.isNewSession, sessionId, accessToken, attributes);
4127
+ request = requestFromMessage(message, userId, this.isNewSession, sessionId, accessToken, attributes, this.visitorInfo);
3943
4128
  this.emit("new message", request);
3944
4129
  return [2 /*return*/];
3945
4130
  });
@@ -3955,34 +4140,61 @@ var StentorRouterChat = /** @class */ (function () {
3955
4140
  else {
3956
4141
  this._userId = "stentor-widget-user-".concat(uuid_1());
3957
4142
  }
3958
- if (get("sessionId") !== "") {
4143
+ var joinSessionId = new URL(window.location.href).searchParams.get("sessionId");
4144
+ if (joinSessionId) {
4145
+ this._sessionId = joinSessionId;
4146
+ set$1("sessionId", this._sessionId);
4147
+ log("Using enforced session id: ".concat(this._sessionId));
4148
+ }
4149
+ else if (get("sessionId")) {
3959
4150
  this._sessionId = get("sessionId");
4151
+ log("Using persisted session id: ".concat(this._sessionId));
3960
4152
  }
3961
4153
  else {
3962
4154
  this._sessionId = "stentor-widget-session-".concat(uuid_1());
3963
4155
  set$1("sessionId", this._sessionId);
4156
+ log("Using generated session id: ".concat(this._sessionId));
3964
4157
  }
3965
- // This is a flag that is cleared after the first message is sent
4158
+ // Always. This triggers a LAUNCH_REQUEST most of the time
3966
4159
  this.isNewSession = true;
4160
+ log("Started session: ".concat(this._sessionId));
3967
4161
  };
3968
- Object.defineProperty(StentorRouterChat.prototype, "userId", {
3969
- get: function () {
3970
- return this._userId;
3971
- },
3972
- enumerable: false,
3973
- configurable: true
3974
- });
3975
- Object.defineProperty(StentorRouterChat.prototype, "sessionId", {
3976
- get: function () {
3977
- return this._sessionId;
3978
- },
3979
- enumerable: false,
3980
- configurable: true
3981
- });
3982
4162
  return StentorRouterChat;
3983
4163
  }());
3984
4164
  function senderToNick(sender) {
3985
- return "".concat(sender.deviceId, "-").concat(sender.userId);
4165
+ // Both are agents
4166
+ return sender.deviceId === "Bot" ?
4167
+ "agent:bot:".concat(sender.userId) : "agent:widget:".concat(sender.userId);
4168
+ }
4169
+ /**
4170
+ *
4171
+ * @param check Function that return true/false if the resource is available
4172
+ * @param stepMs check period in ms
4173
+ * @param timeoutMs max wait in ms
4174
+ * @param resource optional resource name. you will see a log message for every check (step)
4175
+ *
4176
+ * @returns the elapsed time in ms (both resolve/reject)
4177
+ */
4178
+ function waitFor(check, stepMs, timeoutMs, resource) {
4179
+ var elapsedMs = 0;
4180
+ var poll = function (resolve, reject) {
4181
+ if (elapsedMs > timeoutMs) {
4182
+ reject(elapsedMs);
4183
+ }
4184
+ else {
4185
+ if (check()) {
4186
+ resolve(elapsedMs);
4187
+ }
4188
+ else {
4189
+ elapsedMs += stepMs;
4190
+ if (resource) {
4191
+ log("Still waiting for ".concat(resource, " (").concat(elapsedMs, " ms)"));
4192
+ }
4193
+ setTimeout(function (_) { return poll(resolve, reject); }, stepMs);
4194
+ }
4195
+ }
4196
+ };
4197
+ return new Promise(poll);
3986
4198
  }
3987
4199
 
3988
4200
  const PACKET_TYPES = Object.create(null); // no Map = no polyfill
@@ -4034,11 +4246,12 @@ const encodeBlobAsBase64 = (data, callback) => {
4034
4246
  const fileReader = new FileReader();
4035
4247
  fileReader.onload = function () {
4036
4248
  const content = fileReader.result.split(",")[1];
4037
- callback("b" + content);
4249
+ callback("b" + (content || ""));
4038
4250
  };
4039
4251
  return fileReader.readAsDataURL(data);
4040
4252
  };
4041
4253
 
4254
+ // imported from https://github.com/socketio/base64-arraybuffer
4042
4255
  const chars = 'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/';
4043
4256
  // Use a lookup table to find the index.
4044
4257
  const lookup$1 = typeof Uint8Array === 'undefined' ? [] : new Uint8Array(256);
@@ -5206,10 +5419,10 @@ function parse$2(str) {
5206
5419
  }
5207
5420
  function pathNames(obj, path) {
5208
5421
  const regx = /\/{2,9}/g, names = path.replace(regx, "/").split("/");
5209
- if (path.substr(0, 1) == '/' || path.length === 0) {
5422
+ if (path.slice(0, 1) == '/' || path.length === 0) {
5210
5423
  names.splice(0, 1);
5211
5424
  }
5212
- if (path.substr(path.length - 1, 1) == '/') {
5425
+ if (path.slice(-1) == '/') {
5213
5426
  names.splice(names.length - 1, 1);
5214
5427
  }
5215
5428
  return names;
@@ -5302,13 +5515,14 @@ class Socket$1 extends Emitter_1 {
5302
5515
  // Firefox closes the connection when the "beforeunload" event is emitted but not Chrome. This event listener
5303
5516
  // ensures every browser behaves the same (no "disconnect" event at the Socket.IO level when the page is
5304
5517
  // closed/reloaded)
5305
- addEventListener("beforeunload", () => {
5518
+ this.beforeunloadEventListener = () => {
5306
5519
  if (this.transport) {
5307
5520
  // silently close the transport
5308
5521
  this.transport.removeAllListeners();
5309
5522
  this.transport.close();
5310
5523
  }
5311
- }, false);
5524
+ };
5525
+ addEventListener("beforeunload", this.beforeunloadEventListener, false);
5312
5526
  }
5313
5527
  if (this.hostname !== "localhost") {
5314
5528
  this.offlineEventListener = () => {
@@ -5762,6 +5976,7 @@ class Socket$1 extends Emitter_1 {
5762
5976
  // ignore further transport communication
5763
5977
  this.transport.removeAllListeners();
5764
5978
  if (typeof removeEventListener === "function") {
5979
+ removeEventListener("beforeunload", this.beforeunloadEventListener, false);
5765
5980
  removeEventListener("offline", this.offlineEventListener, false);
5766
5981
  }
5767
5982
  // set ready state
@@ -5959,14 +6174,22 @@ function _deconstructPacket(data, buffers) {
5959
6174
  */
5960
6175
  function reconstructPacket(packet, buffers) {
5961
6176
  packet.data = _reconstructPacket(packet.data, buffers);
5962
- packet.attachments = undefined; // no longer useful
6177
+ delete packet.attachments; // no longer useful
5963
6178
  return packet;
5964
6179
  }
5965
6180
  function _reconstructPacket(data, buffers) {
5966
6181
  if (!data)
5967
6182
  return data;
5968
- if (data && data._placeholder) {
5969
- return buffers[data.num]; // appropriate buffer (should be natural order anyway)
6183
+ if (data && data._placeholder === true) {
6184
+ const isIndexValid = typeof data.num === "number" &&
6185
+ data.num >= 0 &&
6186
+ data.num < buffers.length;
6187
+ if (isIndexValid) {
6188
+ return buffers[data.num]; // appropriate buffer (should be natural order anyway)
6189
+ }
6190
+ else {
6191
+ throw new Error("illegal attachments");
6192
+ }
5970
6193
  }
5971
6194
  else if (Array.isArray(data)) {
5972
6195
  for (let i = 0; i < data.length; i++) {
@@ -6020,11 +6243,14 @@ class Encoder {
6020
6243
  encode(obj) {
6021
6244
  if (obj.type === PacketType.EVENT || obj.type === PacketType.ACK) {
6022
6245
  if (hasBinary(obj)) {
6023
- obj.type =
6024
- obj.type === PacketType.EVENT
6246
+ return this.encodeAsBinary({
6247
+ type: obj.type === PacketType.EVENT
6025
6248
  ? PacketType.BINARY_EVENT
6026
- : PacketType.BINARY_ACK;
6027
- return this.encodeAsBinary(obj);
6249
+ : PacketType.BINARY_ACK,
6250
+ nsp: obj.nsp,
6251
+ data: obj.data,
6252
+ id: obj.id,
6253
+ });
6028
6254
  }
6029
6255
  }
6030
6256
  return [this.encodeAsString(obj)];
@@ -6091,9 +6317,13 @@ class Decoder extends Emitter_1 {
6091
6317
  add(obj) {
6092
6318
  let packet;
6093
6319
  if (typeof obj === "string") {
6320
+ if (this.reconstructor) {
6321
+ throw new Error("got plaintext data when reconstructing a packet");
6322
+ }
6094
6323
  packet = this.decodeString(obj);
6095
- if (packet.type === PacketType.BINARY_EVENT ||
6096
- packet.type === PacketType.BINARY_ACK) {
6324
+ const isBinaryEvent = packet.type === PacketType.BINARY_EVENT;
6325
+ if (isBinaryEvent || packet.type === PacketType.BINARY_ACK) {
6326
+ packet.type = isBinaryEvent ? PacketType.EVENT : PacketType.ACK;
6097
6327
  // binary packet's json
6098
6328
  this.reconstructor = new BinaryReconstructor(packet);
6099
6329
  // no attachments, labeled binary but no binary data to follow
@@ -6222,6 +6452,7 @@ class Decoder extends Emitter_1 {
6222
6452
  destroy() {
6223
6453
  if (this.reconstructor) {
6224
6454
  this.reconstructor.finishedReconstruction();
6455
+ this.reconstructor = null;
6225
6456
  }
6226
6457
  }
6227
6458
  }
@@ -7490,6 +7721,20 @@ var StentorServerChat = /** @class */ (function () {
7490
7721
  var _a;
7491
7722
  (_a = this.socket) === null || _a === void 0 ? void 0 : _a.disconnect();
7492
7723
  };
7724
+ StentorServerChat.prototype.bargeOut = function (_cb) {
7725
+ return __awaiter$1(this, void 0, void 0, function () {
7726
+ return __generator$1(this, function (_a) {
7727
+ throw new Error("Method not implemented: bargeOut");
7728
+ });
7729
+ });
7730
+ };
7731
+ StentorServerChat.prototype.bargeIn = function (_agentName, _cb) {
7732
+ return __awaiter$1(this, void 0, void 0, function () {
7733
+ return __generator$1(this, function (_a) {
7734
+ throw new Error("Method not implemented: bargeIn");
7735
+ });
7736
+ });
7737
+ };
7493
7738
  return StentorServerChat;
7494
7739
  }());
7495
7740
 
@@ -7991,6 +8236,9 @@ var List = function (props) {
7991
8236
 
7992
8237
  var ListMiddlewareWidget = function (props) {
7993
8238
  var msg = props.msg, ctx = props.ctx;
8239
+ if (!ctx) {
8240
+ throw new TypeError("ctx not provided to ".concat(ListMiddlewareWidget.name));
8241
+ }
7994
8242
  var list = useMemo(function () { return convertFromListDisplay(msg); }, [msg]);
7995
8243
  var handleExecute = useExecuteActionCallback();
7996
8244
  var handleButton = useButtonCallback();
@@ -8353,6 +8601,8 @@ function useChatServerVisitorId() {
8353
8601
  function useGreeting(active) {
8354
8602
  var curr = useChatServerVisitorId();
8355
8603
  var snapshotRef = useRef(null);
8604
+ var ctx = useContext(ChatConfigContext);
8605
+ var isAdmin = ctx.env.isAdmin;
8356
8606
  useEffect(function () {
8357
8607
  if (active) {
8358
8608
  if (snapshotRef.current !== curr) {
@@ -8365,18 +8615,23 @@ function useGreeting(active) {
8365
8615
  accessToken: curr.accessToken,
8366
8616
  attributes: __assign(__assign({}, curr.attributes), { currentUrl: window.location.href })
8367
8617
  }));
8368
- var timeoutId_1 = setTimeout(function () {
8369
- var greetingAction = sendGreeting();
8370
- curr.dispatch(greetingAction);
8371
- }, 1000);
8372
- return function () {
8373
- clearTimeout(timeoutId_1);
8374
- };
8618
+ if (!isAdmin) {
8619
+ var timeoutId_1 = setTimeout(function () {
8620
+ var greetingAction = sendGreeting();
8621
+ curr.dispatch(greetingAction);
8622
+ }, 1000);
8623
+ return function () {
8624
+ clearTimeout(timeoutId_1);
8625
+ };
8626
+ }
8627
+ else {
8628
+ log("Admin widget. Not sending greeting.");
8629
+ }
8375
8630
  }
8376
8631
  }
8377
8632
  }
8378
8633
  return undefined;
8379
- }, [curr, active]);
8634
+ }, [curr, active, isAdmin]);
8380
8635
  }
8381
8636
 
8382
8637
  function useSuggestionsFetch(search, context) {
@@ -8454,6 +8709,39 @@ function useSuggestions(search, context) {
8454
8709
  }); }, [suggestions, suggestionIndex, execute, suggestionItem]);
8455
8710
  }
8456
8711
 
8712
+ var AdminBar = function (_props) {
8713
+ var name = useRef(null);
8714
+ // We can manage this locally
8715
+ // const hasAdminJoined = useSelector<ChatState, boolean | undefined>(state => state.hasAdminJoined);
8716
+ var _a = useState(false), joined = _a[0], setJoined = _a[1];
8717
+ var dispatch = useChatServerDispatch();
8718
+ function onSubmit(event) {
8719
+ var _a;
8720
+ event.preventDefault();
8721
+ if (!joined) {
8722
+ dispatch(sendBargeIn((_a = name.current) === null || _a === void 0 ? void 0 : _a.value));
8723
+ setJoined(true);
8724
+ }
8725
+ else {
8726
+ dispatch(sendBargeOut());
8727
+ setJoined(false);
8728
+ }
8729
+ }
8730
+ function renderJoin() {
8731
+ return (React$1.createElement("form", { className: "xappw-admin-input-form", onSubmit: onSubmit },
8732
+ React$1.createElement("div", { className: "xappw-admin-input-form__buttons" },
8733
+ React$1.createElement(ActionButton, { addClass: "xappw-admin-input-form__btn", type: "submit", label: "Join" })),
8734
+ React$1.createElement("div", { className: "xappw-admin-input" },
8735
+ React$1.createElement("input", { ref: name, id: "adminBarInput", placeholder: "Type your name here...", className: "xappw-admin-input__input" }))));
8736
+ }
8737
+ function renderLeave() {
8738
+ return (React$1.createElement("form", { className: "xappw-admin-input-form", onSubmit: onSubmit },
8739
+ React$1.createElement("div", { className: "xappw-admin-input-form__buttons" },
8740
+ React$1.createElement(ActionButton, { addClass: "xappw-admin-input-form__btn", type: "submit", label: "Leave" }))));
8741
+ }
8742
+ return (React$1.createElement("div", { className: "xappw-admin-input-container visible" }, joined ? renderLeave() : renderJoin()));
8743
+ };
8744
+
8457
8745
  var ChatBranding = function (props) {
8458
8746
  var text = props.text;
8459
8747
  return (React$1.createElement("div", { className: "chat-footer__branding" }, text !== null && text !== void 0 ? text : "Powered by XAPP AI"));
@@ -8652,6 +8940,7 @@ var ChatFooter = function (props) {
8652
8940
  React$1.createElement("div", { className: "chat-footer__menu-icon" },
8653
8941
  React$1.createElement(DrawerBars, { tabIndex: menuButtonTabIndex, onToggle: toggleDrawer }))) : React$1.createElement(React$1.Fragment, null),
8654
8942
  ((_d = suggestions.suggestions) === null || _d === void 0 ? void 0 : _d.length) > 0 && React$1.createElement(Suggestions, { className: "xappw-chat-footer__suggestions", data: suggestions.suggestions, index: suggestions.index, onItemClick: handleItemClick, onItemUse: handleItemUse }),
8943
+ props.isAdmin && props.isChatting && props.visible && React$1.createElement(AdminBar, null),
8655
8944
  React$1.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,
8656
8945
  // onFocus={this.inputOnFocus}
8657
8946
  onFileUpload: props.onFileUpload }),
@@ -31059,15 +31348,15 @@ var TypingIndicator = function (_) {
31059
31348
  * Show the agent is typing (or the bot - for fun)
31060
31349
  */
31061
31350
  var TypingStatus = function (props) {
31062
- var agent_names = Object.values(props.agents).filter(function (agent) { return agent.typing; });
31063
- return (React$1.createElement(React$1.Fragment, null, agent_names.map(function (agent) {
31351
+ var agentsTyping = Object.values(props.agents).filter(function (agent) { return agent.typing; });
31352
+ return (React$1.createElement(React$1.Fragment, null, agentsTyping.map(function (agent) {
31064
31353
  var _a, _b;
31065
31354
  return (React$1.createElement(React$1.Fragment, null, !props.textTypingStatusEnabled ? (React$1.createElement("div", { className: "chat-msg-container-wrapper", key: "typing-status-".concat(agent.user.nick) },
31066
31355
  React$1.createElement("div", { key: agent.user.nick, className: "chat-msg-container agent chat-typing-progress" },
31067
31356
  React$1.createElement(ChatMessagePart, { user: agent.user, showAvatar: true },
31068
31357
  React$1.createElement("div", { className: "chat-msg" },
31069
31358
  React$1.createElement(ChatMessageBubble, { owner: "others", hasTail: true },
31070
- React$1.createElement(TypingIndicator, null))))))) : (React$1.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",
31359
+ React$1.createElement(TypingIndicator, null))))))) : (React$1.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",
31071
31360
  " is typing"))));
31072
31361
  })));
31073
31362
  };
@@ -31116,9 +31405,18 @@ var MessageList = function (props) {
31116
31405
  */
31117
31406
  function renderByType(msg, sibling) {
31118
31407
  var _a;
31119
- var user = ((_a = props.agents[msg.user.nick]) === null || _a === void 0 ? void 0 : _a.user) || props.agent;
31120
- if (!user) {
31121
- console.warn("Could not get a user from agents list from ".concat(msg.user.nick, " or has an "));
31408
+ var user;
31409
+ // visitor is this widget
31410
+ if (msg.user.nick.startsWith("visitor:")) {
31411
+ user = msg.user;
31412
+ }
31413
+ else {
31414
+ user = ((_a = props.agents[msg.user.nick]) === null || _a === void 0 ? void 0 : _a.user) || props.agent;
31415
+ // Still nothing?
31416
+ if (!user) {
31417
+ console.warn("Could not get a user from agents list with nick: \"".concat(msg.user.nick, "\""));
31418
+ user = msg.user;
31419
+ }
31122
31420
  }
31123
31421
  switch (msg.type) {
31124
31422
  case "chat.file":
@@ -31720,8 +32018,8 @@ var ChatWidget = function (props) {
31720
32018
  });
31721
32019
  }
31722
32020
  }
31723
- useGreeting(!isOffline && !props.preChatFormEnabled && visible);
31724
32021
  var config = props.config, onConnectionStatusChange = props.onConnectionStatusChange;
32022
+ useGreeting(!isOffline && !props.preChatFormEnabled && visible);
31725
32023
  var connectionStatus = chatState.connection.connectionStatus;
31726
32024
  useEffect(function () {
31727
32025
  if (onConnectionStatusChange) {
@@ -31737,7 +32035,7 @@ var ChatWidget = function (props) {
31737
32035
  React$1.createElement("div", { className: "spinner-container ".concat(visible && connectionStatus === "pending" ? "visible" : "") },
31738
32036
  React$1.createElement("div", { className: "spinner" })),
31739
32037
  connectionStatus === "offline" && React$1.createElement(ServerOffline, null),
31740
- React$1.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 }),
32038
+ React$1.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 }),
31741
32039
  React$1.createElement("div", { className: "restartModal", ref: modalRef, onClick: closeModal },
31742
32040
  React$1.createElement(ModalContent, { onClose: closeModal, onReset: refreshOnClick }))),
31743
32041
  React$1.createElement(ChatButton, { addClass: getVisibilityClass(), onClick: chatButtonOnClick, config: (_w = props.config) === null || _w === void 0 ? void 0 : _w.cta, visible: visible })));
@@ -31855,7 +32153,6 @@ function persistStateReducer(storage, initialState, innerReducer) {
31855
32153
  }
31856
32154
 
31857
32155
  function connectionReducer(state, action) {
31858
- log("action", action);
31859
32156
  switch (action.type) {
31860
32157
  case "connection_update":
31861
32158
  return __assign(__assign({}, state), { connectionStatus: action.detail.status });
@@ -31872,31 +32169,32 @@ function joinMessages(messages, msg) {
31872
32169
  }
31873
32170
 
31874
32171
  function memberJoin(state, detail) {
31875
- var _a;
31876
32172
  if (state.chats.length === 0) {
31877
32173
  set$1("sessionId", "");
31878
32174
  }
32175
+ var agents = __assign({}, state.agents);
32176
+ var prevAgentInfo = state.agents[detail.user.nick];
32177
+ agents[detail.user.nick] = __assign(__assign({}, prevAgentInfo), { user: __assign(__assign({}, detail.user), { displayName: detail.user.displayName || "Agent" }), joined: true, typing: false });
31879
32178
  if (isAgent(detail.user.nick)) {
31880
- var prevAgentInfo = state.agents[detail.user.nick];
31881
- return __assign(__assign({}, state), { isChatting: true, chats: (prevAgentInfo === null || prevAgentInfo === void 0 ? void 0 : prevAgentInfo.joined) ? state.chats : joinMessages(state.chats, detail), agents: (_a = {},
31882
- _a[detail.user.nick] = __assign(__assign({}, prevAgentInfo), { user: __assign(__assign({}, detail.user), { displayName: detail.user.displayName || "Bot" }), joined: true, typing: false }),
31883
- _a) });
32179
+ return __assign(__assign({}, state), { isChatting: true, chats: (prevAgentInfo === null || prevAgentInfo === void 0 ? void 0 : prevAgentInfo.joined) ? state.chats : joinMessages(state.chats, detail), agents: agents });
31884
32180
  }
31885
32181
  else {
31886
- return __assign(__assign({}, state), { isChatting: true, chats: joinMessages(state.chats, detail) });
32182
+ return __assign(__assign({}, state), { isChatting: true, chats: joinMessages(state.chats, detail), agents: agents });
31887
32183
  }
31888
32184
  }
31889
32185
 
31890
32186
  function memberLeave(state, detail) {
31891
- var _a;
32187
+ var agents = __assign({}, state.agents);
32188
+ var prevAgentInfo = state.agents[detail.user.nick];
32189
+ agents[detail.user.nick] = __assign(__assign({}, prevAgentInfo), { joined: false, typing: false });
32190
+ // count number of agents that are still joined
32191
+ var agentsJoined = Object.values(agents).filter(function (agent) { return agent.joined; });
32192
+ var isChatting = agentsJoined.length > 0;
31892
32193
  if (isAgent(detail.user.nick)) {
31893
- var prevAgentInfo = state.agents[detail.user.nick];
31894
- return __assign(__assign({}, state), { isChatting: false, chats: (prevAgentInfo === null || prevAgentInfo === void 0 ? void 0 : prevAgentInfo.joined) ? joinMessages(state.chats, detail) : state.chats, agents: (_a = {},
31895
- _a[detail.user.nick] = __assign(__assign({}, prevAgentInfo), { joined: false }),
31896
- _a) });
32194
+ return __assign(__assign({}, state), { isChatting: isChatting, chats: (prevAgentInfo === null || prevAgentInfo === void 0 ? void 0 : prevAgentInfo.joined) ? joinMessages(state.chats, detail) : state.chats, agents: agents });
31897
32195
  }
31898
32196
  else {
31899
- return __assign(__assign({}, state), { isChatting: false, chats: joinMessages(state.chats, detail) });
32197
+ return __assign(__assign({}, state), { isChatting: isChatting, chats: joinMessages(state.chats, detail), agents: agents });
31900
32198
  }
31901
32199
  }
31902
32200
 
@@ -31926,15 +32224,19 @@ function update(state, action) {
31926
32224
  if (action.type === "reset") {
31927
32225
  return resetReducer(state);
31928
32226
  }
31929
- // workaround until state is split. Use combineReducers afterwards
31930
- var newConnectionState = connectionReducer(state.connection, action);
31931
- if (state.connection !== newConnectionState) {
31932
- state = __assign(__assign({}, state), { connection: newConnectionState });
31933
- }
31934
32227
  if (action.detail) {
31935
32228
  state.lastTimestamp = action.detail.timestamp;
31936
32229
  }
31937
32230
  switch (action.type) {
32231
+ case "connection_update":
32232
+ case "receiveToken":
32233
+ case "sendGreeting":
32234
+ // workaround until state is split. Use combineReducers afterwards
32235
+ var newConnectionState = connectionReducer(state.connection, action);
32236
+ if (state.connection !== newConnectionState) {
32237
+ state = __assign(__assign({}, state), { connection: newConnectionState });
32238
+ }
32239
+ return state;
31938
32240
  case "account_status":
31939
32241
  return __assign(__assign({}, state), { accountStatus: action.detail.status });
31940
32242
  case "department_update":