@microsoft/omnichannel-chat-widget 1.8.2-main.fc93d3d → 1.8.3-main.38c88a7
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +46 -1
- package/lib/cjs/common/Constants.js +8 -2
- package/lib/cjs/common/telemetry/TelemetryConstants.js +2 -0
- package/lib/cjs/common/utils.js +27 -2
- package/lib/cjs/components/chatbuttonstateful/ChatButtonStateful.js +4 -4
- package/lib/cjs/components/livechatwidget/common/createInternetConnectionChangeHandler.js +22 -9
- package/lib/cjs/components/livechatwidget/common/createMarkdown.js +54 -1
- package/lib/cjs/components/livechatwidget/common/customEventHandler.js +53 -0
- package/lib/cjs/components/livechatwidget/common/endChat.js +1 -0
- package/lib/cjs/components/livechatwidget/common/initWebChatComposer.js +5 -1
- package/lib/cjs/components/livechatwidget/common/renderSurveyHelpers.js +23 -0
- package/lib/cjs/components/livechatwidget/common/startChat.js +1 -1
- package/lib/cjs/components/livechatwidget/livechatwidgetstateful/LiveChatWidgetStateful.js +5 -1
- package/lib/cjs/components/webchatcontainerstateful/WebChatContainerStateful.js +1 -1
- package/lib/cjs/components/webchatcontainerstateful/common/DesignerChatAdapter.js +3 -1
- package/lib/cjs/components/webchatcontainerstateful/common/utils/chatAdapterUtils.js +27 -2
- package/lib/cjs/components/webchatcontainerstateful/webchatcontroller/middlewares/storemiddlewares/callActionMiddleware.js +42 -0
- package/lib/cjs/components/webchatcontainerstateful/webchatcontroller/middlewares/storemiddlewares/customEventMiddleware.js +41 -0
- package/lib/cjs/components/webchatcontainerstateful/webchatcontroller/middlewares/storemiddlewares/queueOverflowHandlerMiddleware.js +45 -0
- package/lib/cjs/contexts/common/CustomEventType.js +1 -0
- package/lib/cjs/firstresponselatency/FirstMessageTrackerFromBot.js +101 -36
- package/lib/cjs/firstresponselatency/FirstResponseLatencyTracker.js +39 -21
- package/lib/cjs/firstresponselatency/util.js +12 -8
- package/lib/cjs/plugins/createChatTranscript.js +13 -0
- package/lib/esm/common/Constants.js +8 -2
- package/lib/esm/common/telemetry/TelemetryConstants.js +2 -0
- package/lib/esm/common/utils.js +21 -0
- package/lib/esm/components/chatbuttonstateful/ChatButtonStateful.js +4 -4
- package/lib/esm/components/livechatwidget/common/createInternetConnectionChangeHandler.js +22 -9
- package/lib/esm/components/livechatwidget/common/createMarkdown.js +54 -1
- package/lib/esm/components/livechatwidget/common/customEventHandler.js +45 -0
- package/lib/esm/components/livechatwidget/common/endChat.js +1 -0
- package/lib/esm/components/livechatwidget/common/initWebChatComposer.js +5 -1
- package/lib/esm/components/livechatwidget/common/renderSurveyHelpers.js +23 -0
- package/lib/esm/components/livechatwidget/common/startChat.js +1 -1
- package/lib/esm/components/livechatwidget/livechatwidgetstateful/LiveChatWidgetStateful.js +5 -1
- package/lib/esm/components/webchatcontainerstateful/WebChatContainerStateful.js +1 -1
- package/lib/esm/components/webchatcontainerstateful/common/DesignerChatAdapter.js +4 -2
- package/lib/esm/components/webchatcontainerstateful/common/utils/chatAdapterUtils.js +23 -0
- package/lib/esm/components/webchatcontainerstateful/webchatcontroller/middlewares/storemiddlewares/callActionMiddleware.js +36 -0
- package/lib/esm/components/webchatcontainerstateful/webchatcontroller/middlewares/storemiddlewares/customEventMiddleware.js +33 -0
- package/lib/esm/components/webchatcontainerstateful/webchatcontroller/middlewares/storemiddlewares/queueOverflowHandlerMiddleware.js +38 -0
- package/lib/esm/contexts/common/CustomEventType.js +1 -0
- package/lib/esm/firstresponselatency/FirstMessageTrackerFromBot.js +101 -36
- package/lib/esm/firstresponselatency/FirstResponseLatencyTracker.js +39 -21
- package/lib/esm/firstresponselatency/util.js +12 -8
- package/lib/esm/plugins/createChatTranscript.js +13 -0
- package/lib/types/common/Constants.d.ts +8 -2
- package/lib/types/common/telemetry/TelemetryConstants.d.ts +2 -0
- package/lib/types/common/utils.d.ts +8 -0
- package/lib/types/components/livechatwidget/common/customEventHandler.d.ts +4 -0
- package/lib/types/components/webchatcontainerstateful/common/utils/chatAdapterUtils.d.ts +2 -0
- package/lib/types/components/webchatcontainerstateful/webchatcontroller/middlewares/storemiddlewares/callActionMiddleware.d.ts +8 -0
- package/lib/types/components/webchatcontainerstateful/webchatcontroller/middlewares/storemiddlewares/customEventMiddleware.d.ts +22 -0
- package/lib/types/components/webchatcontainerstateful/webchatcontroller/middlewares/storemiddlewares/queueOverflowHandlerMiddleware.d.ts +5 -0
- package/lib/types/contexts/common/CustomEventType.d.ts +6 -0
- package/lib/types/firstresponselatency/FirstResponseLatencyTracker.d.ts +2 -2
- package/package.json +3 -3
|
@@ -7,54 +7,96 @@ import { createTrackingMessage } from "./util";
|
|
|
7
7
|
// with different timeline, therefore this is a functional approach to track the events, instead of a class based approach
|
|
8
8
|
export const createTrackingForFirstMessage = () => {
|
|
9
9
|
// Reset the tracking variables
|
|
10
|
-
let
|
|
11
|
-
let stopTracking = false;
|
|
10
|
+
let isTracking = false;
|
|
12
11
|
let startTime = 0;
|
|
13
12
|
let stopTime = 0;
|
|
14
|
-
let stopTrackingMessage;
|
|
13
|
+
let stopTrackingMessage = null;
|
|
15
14
|
let flag = false;
|
|
15
|
+
let trackingTimeoutId;
|
|
16
|
+
|
|
17
|
+
/**
|
|
18
|
+
* Checks if the message payload is from a valid sender (not an agent).
|
|
19
|
+
* Returns false if the message is from an agent (tag 'public'), true otherwise.
|
|
20
|
+
*/
|
|
16
21
|
const isMessageFromValidSender = payload => {
|
|
17
22
|
var _payload$tags;
|
|
18
|
-
// agent scenario
|
|
19
23
|
if (payload !== null && payload !== void 0 && (_payload$tags = payload.tags) !== null && _payload$tags !== void 0 && _payload$tags.includes("public")) {
|
|
20
24
|
return false;
|
|
21
25
|
}
|
|
22
26
|
return true;
|
|
23
27
|
};
|
|
28
|
+
|
|
29
|
+
/**
|
|
30
|
+
* Listener for widget load completion event.
|
|
31
|
+
* Starts tracking the time for the first bot message after widget loads.
|
|
32
|
+
* Sets a 5-second timeout to auto-reset if no bot message is received.
|
|
33
|
+
*/
|
|
24
34
|
const widgetLoadListener = BroadcastService.getMessageByEventName(TelemetryEvent.WidgetLoadComplete).subscribe(() => {
|
|
25
|
-
if (
|
|
26
|
-
|
|
35
|
+
if (isTracking) return;
|
|
36
|
+
isTracking = true;
|
|
27
37
|
startTime = new Date().getTime();
|
|
38
|
+
// Start a 5-second timeout to auto-stop tracking if not stopped
|
|
39
|
+
if (trackingTimeoutId) {
|
|
40
|
+
clearTimeout(trackingTimeoutId);
|
|
41
|
+
}
|
|
42
|
+
trackingTimeoutId = setTimeout(() => {
|
|
43
|
+
if (isTracking) {
|
|
44
|
+
// Reset state and disengage, no telemetry or FMLTrackingCompleted
|
|
45
|
+
isTracking = false;
|
|
46
|
+
startTime = 0;
|
|
47
|
+
stopTime = 0;
|
|
48
|
+
stopTrackingMessage = null;
|
|
49
|
+
trackingTimeoutId = undefined;
|
|
50
|
+
disconnectListener();
|
|
51
|
+
}
|
|
52
|
+
}, 10000); //adding more time since it meassures from widget load complete till message received
|
|
28
53
|
});
|
|
54
|
+
|
|
55
|
+
/**
|
|
56
|
+
* Listener for new bot message event.
|
|
57
|
+
* If a valid bot message is received, stops tracking and logs telemetry.
|
|
58
|
+
* If the message is invalid, resets and disengages listeners.
|
|
59
|
+
*/
|
|
29
60
|
const newMessageListener = BroadcastService.getMessageByEventName(BroadcastEvent.NewMessageReceived).subscribe(message => {
|
|
30
61
|
const payload = message.payload;
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
stopTime = new Date().getTime();
|
|
38
|
-
const elapsedTime = stopTime - startTime;
|
|
39
|
-
stopTracking = true;
|
|
40
|
-
stopTrackingMessage = createTrackingMessage(payload, "botMessage");
|
|
41
|
-
notifyFMLTrackingCompleted();
|
|
42
|
-
TelemetryHelper.logActionEvent(LogLevel.INFO, {
|
|
43
|
-
Event: TelemetryEvent.BotFirstMessageLapTrack,
|
|
44
|
-
Description: "First Message from Bot latency tracking",
|
|
45
|
-
CustomProperties: {
|
|
46
|
-
elapsedTime,
|
|
47
|
-
widgetLoadedAt: startTime,
|
|
48
|
-
botMessage: stopTrackingMessage
|
|
49
|
-
}
|
|
50
|
-
});
|
|
62
|
+
if (!isMessageFromValidSender(payload)) {
|
|
63
|
+
// If not valid, stop everything and clean up
|
|
64
|
+
isTracking = false;
|
|
65
|
+
if (trackingTimeoutId) {
|
|
66
|
+
clearTimeout(trackingTimeoutId);
|
|
67
|
+
trackingTimeoutId = undefined;
|
|
51
68
|
}
|
|
69
|
+
disconnectListener();
|
|
70
|
+
return;
|
|
71
|
+
}
|
|
72
|
+
if (isTracking) {
|
|
73
|
+
isTracking = false;
|
|
74
|
+
// Clear the timeout if it exists
|
|
75
|
+
if (trackingTimeoutId) {
|
|
76
|
+
clearTimeout(trackingTimeoutId);
|
|
77
|
+
trackingTimeoutId = undefined;
|
|
78
|
+
}
|
|
79
|
+
stopTime = new Date().getTime();
|
|
80
|
+
const elapsedTime = stopTime - startTime;
|
|
81
|
+
stopTrackingMessage = createTrackingMessage(payload, "botMessage");
|
|
82
|
+
notifyFMLTrackingCompleted();
|
|
83
|
+
TelemetryHelper.logActionEvent(LogLevel.INFO, {
|
|
84
|
+
Event: TelemetryEvent.BotFirstMessageLapTrack,
|
|
85
|
+
Description: "First Message from Bot latency tracking",
|
|
86
|
+
CustomProperties: {
|
|
87
|
+
elapsedTime,
|
|
88
|
+
widgetLoadedAt: startTime,
|
|
89
|
+
botMessage: stopTrackingMessage
|
|
90
|
+
}
|
|
91
|
+
});
|
|
92
|
+
disconnectListener();
|
|
52
93
|
}
|
|
53
|
-
|
|
54
|
-
// this track only first message, if coming from the bot or not
|
|
55
|
-
// the only difference is that it logs only those from bot
|
|
56
|
-
disconnectListener();
|
|
57
94
|
});
|
|
95
|
+
|
|
96
|
+
/**
|
|
97
|
+
* Notifies that FML (First Message Latency) tracking is completed.
|
|
98
|
+
* Retries sending the completion event until acknowledged.
|
|
99
|
+
*/
|
|
58
100
|
const notifyFMLTrackingCompleted = () => {
|
|
59
101
|
ackListener();
|
|
60
102
|
// Retry sending until flag is true, but do not block the main thread
|
|
@@ -69,6 +111,11 @@ export const createTrackingForFirstMessage = () => {
|
|
|
69
111
|
}
|
|
70
112
|
}, 100);
|
|
71
113
|
};
|
|
114
|
+
|
|
115
|
+
/**
|
|
116
|
+
* Listener for FMLTrackingCompletedAck event.
|
|
117
|
+
* Sets the flag to true when acknowledgment is received.
|
|
118
|
+
*/
|
|
72
119
|
const ackListener = () => {
|
|
73
120
|
const listen = BroadcastService.getMessageByEventName(BroadcastEvent.FMLTrackingCompletedAck).subscribe(() => {
|
|
74
121
|
flag = true;
|
|
@@ -78,22 +125,32 @@ export const createTrackingForFirstMessage = () => {
|
|
|
78
125
|
|
|
79
126
|
// Rehydrate message is received when the widget is reloaded, this is to ensure that we are not tracking messages that are not part of the current conversation
|
|
80
127
|
// No need to keep listerning for tracking, enforcing disconnection for the listners
|
|
128
|
+
/**
|
|
129
|
+
* Listener for widget rehydration event.
|
|
130
|
+
* Resets tracking and disconnects listeners when widget is reloaded.
|
|
131
|
+
*/
|
|
81
132
|
const rehydrateListener = BroadcastService.getMessageByEventName(TelemetryEvent.RehydrateMessageReceived).subscribe(() => {
|
|
82
|
-
|
|
83
|
-
stopTracking = false;
|
|
133
|
+
isTracking = false;
|
|
84
134
|
disconnectListener();
|
|
85
135
|
});
|
|
86
136
|
|
|
87
137
|
// Rehydrate message is received when the widget is reloaded, this is to ensure that we are not tracking messages that are not part of the current conversation
|
|
88
138
|
// No need to keep listerning for tracking, enforcing disconnection for the listners
|
|
139
|
+
/**
|
|
140
|
+
* Listener for history message event.
|
|
141
|
+
* Resets tracking and disconnects listeners when history is loaded.
|
|
142
|
+
*/
|
|
89
143
|
const historyListener = BroadcastService.getMessageByEventName(BroadcastEvent.HistoryMessageReceived).subscribe(() => {
|
|
90
|
-
|
|
91
|
-
stopTracking = false;
|
|
144
|
+
isTracking = false;
|
|
92
145
|
disconnectListener();
|
|
93
146
|
});
|
|
147
|
+
|
|
148
|
+
/**
|
|
149
|
+
* Listener for network disconnection event.
|
|
150
|
+
* Resets tracking, disconnects listeners, and logs a telemetry error.
|
|
151
|
+
*/
|
|
94
152
|
const offlineNetworkListener = BroadcastService.getMessageByEventName(TelemetryEvent.NetworkDisconnected).subscribe(() => {
|
|
95
|
-
|
|
96
|
-
stopTracking = false;
|
|
153
|
+
isTracking = false;
|
|
97
154
|
disconnectListener();
|
|
98
155
|
TelemetryHelper.logActionEvent(LogLevel.INFO, {
|
|
99
156
|
Event: TelemetryEvent.BotFirstMessageLapTrackError,
|
|
@@ -102,7 +159,15 @@ export const createTrackingForFirstMessage = () => {
|
|
|
102
159
|
});
|
|
103
160
|
|
|
104
161
|
// this is to ensure that we are not tracking messages that are not part of the current conversation
|
|
162
|
+
/**
|
|
163
|
+
* Disconnects all listeners and clears the tracking timeout.
|
|
164
|
+
* Used for cleanup when tracking is stopped or reset.
|
|
165
|
+
*/
|
|
105
166
|
const disconnectListener = () => {
|
|
167
|
+
if (trackingTimeoutId) {
|
|
168
|
+
clearTimeout(trackingTimeoutId);
|
|
169
|
+
trackingTimeoutId = undefined;
|
|
170
|
+
}
|
|
106
171
|
historyListener.unsubscribe();
|
|
107
172
|
rehydrateListener.unsubscribe();
|
|
108
173
|
newMessageListener.unsubscribe();
|
|
@@ -11,14 +11,13 @@ export let FirstResponseLatencyTracker = /*#__PURE__*/function () {
|
|
|
11
11
|
function FirstResponseLatencyTracker() {
|
|
12
12
|
_classCallCheck(this, FirstResponseLatencyTracker);
|
|
13
13
|
_defineProperty(this, "isABotConversation", false);
|
|
14
|
-
_defineProperty(this, "
|
|
15
|
-
_defineProperty(this, "isEnded", false);
|
|
14
|
+
_defineProperty(this, "isTracking", false);
|
|
16
15
|
_defineProperty(this, "startTrackingMessage", void 0);
|
|
17
16
|
_defineProperty(this, "stopTrackingMessage", void 0);
|
|
18
17
|
_defineProperty(this, "isReady", false);
|
|
18
|
+
_defineProperty(this, "trackingTimeoutId", void 0);
|
|
19
19
|
_defineProperty(this, "offlineNetworkListener", BroadcastService.getMessageByEventName(TelemetryEvent.NetworkDisconnected).subscribe(() => {
|
|
20
|
-
this.
|
|
21
|
-
this.isEnded = false;
|
|
20
|
+
this.isTracking = false;
|
|
22
21
|
TelemetryHelper.logActionEvent(LogLevel.INFO, {
|
|
23
22
|
Event: TelemetryEvent.MessageStopLapTrackError,
|
|
24
23
|
Description: "Tracker Stopped due to network disconnection"
|
|
@@ -66,7 +65,7 @@ export let FirstResponseLatencyTracker = /*#__PURE__*/function () {
|
|
|
66
65
|
value: function startTracking(payload) {
|
|
67
66
|
if (!this.isReady) return;
|
|
68
67
|
// this prevents to initiate tracking for multiple incoming messages
|
|
69
|
-
if (this.
|
|
68
|
+
if (this.isTracking) {
|
|
70
69
|
return;
|
|
71
70
|
}
|
|
72
71
|
// this is to ensure we track only messages where bot is engaged
|
|
@@ -74,10 +73,24 @@ export let FirstResponseLatencyTracker = /*#__PURE__*/function () {
|
|
|
74
73
|
return;
|
|
75
74
|
}
|
|
76
75
|
// control of states to prevent clashing of messages
|
|
77
|
-
this.
|
|
78
|
-
this.isEnded = false;
|
|
76
|
+
this.isTracking = true;
|
|
79
77
|
// The idea of using types is to enrich telemetry data
|
|
80
78
|
this.startTrackingMessage = this.createTrackingMessage(payload, "userMessage");
|
|
79
|
+
|
|
80
|
+
// Start a 5-second timeout to auto-stop tracking if not stopped
|
|
81
|
+
if (this.trackingTimeoutId) {
|
|
82
|
+
clearTimeout(this.trackingTimeoutId);
|
|
83
|
+
}
|
|
84
|
+
this.trackingTimeoutId = setTimeout(() => {
|
|
85
|
+
// this means the start process is in progress, but the end wasn't called within the time limit
|
|
86
|
+
if (this.isTracking) {
|
|
87
|
+
// Reset state variables and skip stopTracking
|
|
88
|
+
this.isTracking = false;
|
|
89
|
+
this.startTrackingMessage = undefined;
|
|
90
|
+
this.stopTrackingMessage = undefined;
|
|
91
|
+
this.trackingTimeoutId = undefined;
|
|
92
|
+
}
|
|
93
|
+
}, 5000);
|
|
81
94
|
}
|
|
82
95
|
}, {
|
|
83
96
|
key: "handleAgentMessage",
|
|
@@ -93,13 +106,16 @@ export let FirstResponseLatencyTracker = /*#__PURE__*/function () {
|
|
|
93
106
|
value: function stopTracking(payload) {
|
|
94
107
|
var _this$stopTrackingMes, _this$startTrackingMe;
|
|
95
108
|
// this prevents execution for multiple incoming messages from the bot.
|
|
96
|
-
if (
|
|
109
|
+
if (!this.isTracking) {
|
|
97
110
|
return;
|
|
98
111
|
}
|
|
99
|
-
|
|
112
|
+
// Clear the timeout if it exists
|
|
113
|
+
if (this.trackingTimeoutId) {
|
|
114
|
+
clearTimeout(this.trackingTimeoutId);
|
|
115
|
+
this.trackingTimeoutId = undefined;
|
|
116
|
+
}
|
|
100
117
|
// control of states to prevent clashing of messages
|
|
101
|
-
this.
|
|
102
|
-
this.isStarted = false;
|
|
118
|
+
this.isTracking = false;
|
|
103
119
|
|
|
104
120
|
// The idea of using types is to enrich telemetry data
|
|
105
121
|
this.stopTrackingMessage = this.createTrackingMessage(payload, "botMessage");
|
|
@@ -154,12 +170,16 @@ export let FirstResponseLatencyTracker = /*#__PURE__*/function () {
|
|
|
154
170
|
if (!payload || !payload.Id) {
|
|
155
171
|
throw new Error("Invalid payload");
|
|
156
172
|
}
|
|
157
|
-
|
|
158
|
-
if
|
|
173
|
+
|
|
174
|
+
// Only allow stopTracking if sender is valid and tracking is active
|
|
175
|
+
if (!this.isMessageFromValidSender(payload)) {
|
|
176
|
+
// Do not change isTracking or stopTrackingMessage
|
|
177
|
+
return;
|
|
178
|
+
}
|
|
179
|
+
if (this.isABotConversation && this.isTracking) {
|
|
159
180
|
this.stopTracking(payload);
|
|
160
181
|
}
|
|
161
182
|
} catch (e) {
|
|
162
|
-
console.error("FRL : error while trying to stop the tracker", e);
|
|
163
183
|
TelemetryHelper.logActionEvent(LogLevel.ERROR, {
|
|
164
184
|
Event: TelemetryEvent.MessageStopLapTrackError,
|
|
165
185
|
Description: "Error while stopping the clock",
|
|
@@ -168,11 +188,6 @@ export let FirstResponseLatencyTracker = /*#__PURE__*/function () {
|
|
|
168
188
|
payload: payload
|
|
169
189
|
}
|
|
170
190
|
});
|
|
171
|
-
//reset state
|
|
172
|
-
this.startTrackingMessage = undefined;
|
|
173
|
-
this.stopTrackingMessage = undefined;
|
|
174
|
-
this.isStarted = false;
|
|
175
|
-
this.isEnded = false;
|
|
176
191
|
}
|
|
177
192
|
}
|
|
178
193
|
}, {
|
|
@@ -180,10 +195,13 @@ export let FirstResponseLatencyTracker = /*#__PURE__*/function () {
|
|
|
180
195
|
value: function deregister() {
|
|
181
196
|
// Reset State
|
|
182
197
|
this.isABotConversation = false;
|
|
183
|
-
this.
|
|
184
|
-
this.isEnded = false;
|
|
198
|
+
this.isTracking = false;
|
|
185
199
|
this.startTrackingMessage = undefined;
|
|
186
200
|
this.stopTrackingMessage = undefined;
|
|
201
|
+
if (this.trackingTimeoutId) {
|
|
202
|
+
clearTimeout(this.trackingTimeoutId);
|
|
203
|
+
this.trackingTimeoutId = undefined;
|
|
204
|
+
}
|
|
187
205
|
this.offlineNetworkListener.unsubscribe();
|
|
188
206
|
this.fmltrackingListener.unsubscribe();
|
|
189
207
|
this.rehydrateListener.unsubscribe();
|
|
@@ -1,5 +1,7 @@
|
|
|
1
1
|
import { ScenarioType } from "./Constants";
|
|
2
2
|
import { Constants } from "../common/Constants";
|
|
3
|
+
const DELTA_WITHIN_LIMITS_IN_MS = 250;
|
|
4
|
+
|
|
3
5
|
/**
|
|
4
6
|
* Determines whether a given activity is a historical message.
|
|
5
7
|
*
|
|
@@ -17,19 +19,21 @@ import { Constants } from "../common/Constants";
|
|
|
17
19
|
* - If the ID is valid and the timestamp is older than the start time, the message is historical.
|
|
18
20
|
*/
|
|
19
21
|
export const isHistoryMessage = (activity, startTime) => {
|
|
20
|
-
var _activity$channelData
|
|
22
|
+
var _activity$channelData;
|
|
21
23
|
// Only process message activities
|
|
22
24
|
if ((activity === null || activity === void 0 ? void 0 : activity.type) !== Constants.message) {
|
|
23
25
|
return false;
|
|
24
26
|
}
|
|
25
27
|
|
|
26
|
-
//
|
|
27
|
-
if (activity !== null && activity !== void 0 && (_activity$channelData = activity.channelData) !== null && _activity$channelData !== void 0 &&
|
|
28
|
+
// Prioritize legacy history tag
|
|
29
|
+
if (activity !== null && activity !== void 0 && (_activity$channelData = activity.channelData) !== null && _activity$channelData !== void 0 && _activity$channelData.tags && activity.channelData.tags.includes(Constants.historyMessageTag)) {
|
|
28
30
|
return true;
|
|
29
31
|
}
|
|
30
32
|
const activityId = extractTimestampFromId(activity);
|
|
31
33
|
const isValidId = !isNaN(activityId) && activityId > 0;
|
|
32
|
-
const
|
|
34
|
+
const difference = startTime - activityId;
|
|
35
|
+
// Only consider historical if activityId < startTime and difference >= DELTA_WITHIN_LIMITS_IN_MS
|
|
36
|
+
const isOlderThanStartTime = activityId < startTime && difference >= DELTA_WITHIN_LIMITS_IN_MS;
|
|
33
37
|
const isHistoryById = isValidId && isOlderThanStartTime;
|
|
34
38
|
return isHistoryById;
|
|
35
39
|
};
|
|
@@ -56,7 +60,7 @@ export const extractTimestampFromId = activity => {
|
|
|
56
60
|
return activityId;
|
|
57
61
|
};
|
|
58
62
|
export const buildMessagePayload = (activity, userId) => {
|
|
59
|
-
var _text, _text2, _activity$
|
|
63
|
+
var _text, _text2, _activity$channelData2, _activity$from;
|
|
60
64
|
return {
|
|
61
65
|
// To identify hidden contents vs empty content
|
|
62
66
|
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
|
@@ -64,7 +68,7 @@ export const buildMessagePayload = (activity, userId) => {
|
|
|
64
68
|
type: activity === null || activity === void 0 ? void 0 : activity.type,
|
|
65
69
|
timestamp: activity === null || activity === void 0 ? void 0 : activity.timestamp,
|
|
66
70
|
userId: userId,
|
|
67
|
-
tags: activity === null || activity === void 0 ? void 0 : (_activity$
|
|
71
|
+
tags: (activity === null || activity === void 0 ? void 0 : (_activity$channelData2 = activity.channelData) === null || _activity$channelData2 === void 0 ? void 0 : _activity$channelData2.tags) || [],
|
|
68
72
|
messageType: "",
|
|
69
73
|
Id: activity === null || activity === void 0 ? void 0 : activity.id,
|
|
70
74
|
role: activity === null || activity === void 0 ? void 0 : (_activity$from = activity.from) === null || _activity$from === void 0 ? void 0 : _activity$from.role,
|
|
@@ -88,9 +92,9 @@ export const polyfillMessagePayloadForEvent = (activity, payload, conversationId
|
|
|
88
92
|
};
|
|
89
93
|
};
|
|
90
94
|
export const getScenarioType = activity => {
|
|
91
|
-
var _activity$from3, _activity$
|
|
95
|
+
var _activity$from3, _activity$channelData3;
|
|
92
96
|
const role = activity === null || activity === void 0 ? void 0 : (_activity$from3 = activity.from) === null || _activity$from3 === void 0 ? void 0 : _activity$from3.role;
|
|
93
|
-
const tags = activity === null || activity === void 0 ? void 0 : (_activity$
|
|
97
|
+
const tags = activity === null || activity === void 0 ? void 0 : (_activity$channelData3 = activity.channelData) === null || _activity$channelData3 === void 0 ? void 0 : _activity$channelData3.tags;
|
|
94
98
|
if (role === Constants.userMessageTag) {
|
|
95
99
|
return ScenarioType.UserSendMessageStrategy;
|
|
96
100
|
}
|
|
@@ -700,10 +700,23 @@ const createChatTranscript = async function (transcript, facadeChatSDK) {
|
|
|
700
700
|
reader.readAsDataURL(blob);
|
|
701
701
|
});
|
|
702
702
|
};
|
|
703
|
+
|
|
704
|
+
// Configure DOMPurify to remove target attribute from br tags
|
|
705
|
+
const hook = function (node) {
|
|
706
|
+
// eslint-disable-line @typescript-eslint/no-explicit-any
|
|
707
|
+
// Remove target attribute from br tags as it causes them to display as literal text
|
|
708
|
+
if (node.tagName === "BR" && node.hasAttribute("target")) {
|
|
709
|
+
node.removeAttribute("target");
|
|
710
|
+
}
|
|
711
|
+
};
|
|
712
|
+
DOMPurify.addHook("afterSanitizeAttributes", hook);
|
|
703
713
|
let messages = transcriptMessages.filter(message => {
|
|
704
714
|
message.content = DOMPurify.sanitize(message.content);
|
|
705
715
|
return message;
|
|
706
716
|
});
|
|
717
|
+
|
|
718
|
+
// Clean up the hook after processing all messages
|
|
719
|
+
DOMPurify.removeHook("afterSanitizeAttributes", hook);
|
|
707
720
|
if (renderAttachments) {
|
|
708
721
|
messages = await Promise.all(transcriptMessages.map(async message => {
|
|
709
722
|
// eslint-disable-line @typescript-eslint/no-explicit-any
|
|
@@ -16,6 +16,7 @@ export declare class Constants {
|
|
|
16
16
|
static readonly markdown = "markdown";
|
|
17
17
|
static readonly actionType = "actionType";
|
|
18
18
|
static readonly markDownSystemMessageClass = "webchat__basic-transcript__activity-markdown-body";
|
|
19
|
+
static readonly MARKDOWN_LIST_INDENTATION = " ";
|
|
19
20
|
static readonly String = "string";
|
|
20
21
|
static readonly ChatMessagesJson = "chatMessagesJson";
|
|
21
22
|
static readonly truePascal = "True";
|
|
@@ -83,8 +84,7 @@ export declare class Constants {
|
|
|
83
84
|
static readonly TargetRelationship = "rel";
|
|
84
85
|
static readonly TargetRelationshipAttributes = "noopener noreferrer";
|
|
85
86
|
static readonly OpenLinkIconCssClass = "webchat__render-markdown__external-link-icon";
|
|
86
|
-
static readonly
|
|
87
|
-
static readonly internetConnectionTestUrlText = "Omnichannel Connect Test";
|
|
87
|
+
static readonly internetConnectionTestPath = "/livechatwidget/version.txt";
|
|
88
88
|
static readonly ChatWidgetStateChangedPrefix = "ChatWidgetStateChanged";
|
|
89
89
|
static readonly PostChatLoadingDurationInMs = 2000;
|
|
90
90
|
static readonly BrowserUnloadConfirmationMessage = "Do you want to leave chat?";
|
|
@@ -97,6 +97,12 @@ export declare class Constants {
|
|
|
97
97
|
static readonly OCOriginalMessageId = "OriginalMessageId";
|
|
98
98
|
static readonly WebchatSequenceIdAttribute = "webchat:sequence-id";
|
|
99
99
|
static readonly MessageSequenceIdOverride = "MessageSequenceIdOverride";
|
|
100
|
+
static readonly sendCustomEvent = "sendCustomEvent";
|
|
101
|
+
static readonly onCustomEvent = "onCustomEvent";
|
|
102
|
+
static readonly customEventName = "customEventName";
|
|
103
|
+
static readonly customEventValue = "customEventValue";
|
|
104
|
+
static readonly Hidden = "Hidden";
|
|
105
|
+
static readonly EndConversationDueToOverflow = "endconversationduetooverflow";
|
|
100
106
|
}
|
|
101
107
|
export declare const Regex: {
|
|
102
108
|
new (): {};
|
|
@@ -172,6 +172,7 @@ export declare enum TelemetryEvent {
|
|
|
172
172
|
BotAuthActivityUndefinedSignInId = "BotAuthActivityUndefinedSignInId",
|
|
173
173
|
ThirdPartyCookiesBlocked = "ThirdPartyCookiesBlocked",
|
|
174
174
|
ParticipantsRemovedEvent = "ParticipantsRemovedEvent",
|
|
175
|
+
QueueOverflowEvent = "QueueOverflowEvent",
|
|
175
176
|
ProcessingHTMLTextMiddlewareFailed = "ProcessingHTMLTextMiddlewareFailed",
|
|
176
177
|
ProcessingSanitizationMiddlewareFailed = "ProcessingSanitizationMiddlewareFailed",
|
|
177
178
|
FormatTagsMiddlewareJSONStringifyFailed = "FormatTagsMiddlewareJSONStringifyFailed",
|
|
@@ -210,6 +211,7 @@ export declare enum TelemetryEvent {
|
|
|
210
211
|
SystemMessageReceived = "SystemMessageReceived",
|
|
211
212
|
RehydrateMessageReceived = "RehydrateMessageReceived",
|
|
212
213
|
CustomContextReceived = "CustomContextReceived",
|
|
214
|
+
CustomEventAction = "CustomEventAction",
|
|
213
215
|
NetworkDisconnected = "NetworkDisconnected",
|
|
214
216
|
NetworkReconnected = "NetworkReconnected",
|
|
215
217
|
LinkModePostChatWorkflowStarted = "LinkModePostChatWorkflowStarted",
|
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
import { FacadeChatSDK } from "./facades/FacadeChatSDK";
|
|
2
2
|
import { ITimer } from "./interfaces/ITimer";
|
|
3
|
+
import * as CustomEventType from "../contexts/common/CustomEventType";
|
|
3
4
|
export declare const setTabIndices: (elements: HTMLElement[] | null, tabIndexMap: Map<string, number>, shouldBeFocusable: boolean) => void;
|
|
4
5
|
export declare const findParentFocusableElementsWithoutChildContainer: (elementId: string) => HTMLElement[] | null;
|
|
5
6
|
export declare const findAllFocusableElement: (parent: string | HTMLElement) => any[] | null;
|
|
@@ -47,3 +48,10 @@ export declare const formatTemplateString: (templateMessage: string, values: any
|
|
|
47
48
|
export declare const parseLowerCaseString: (property: string | boolean | undefined) => string;
|
|
48
49
|
export declare const setOcUserAgent: (chatSDK: any) => void;
|
|
49
50
|
export declare function getDeviceType(): string;
|
|
51
|
+
export declare const isValidCustomEvent: (payload: object) => boolean;
|
|
52
|
+
export declare const getCustomEventValue: (customEventPayload: CustomEventType.ICustomEvent) => string;
|
|
53
|
+
export declare function isEndConversationDueToOverflowActivity(activity: {
|
|
54
|
+
channelData?: {
|
|
55
|
+
tags?: string[];
|
|
56
|
+
};
|
|
57
|
+
}): boolean | undefined;
|
|
@@ -0,0 +1,4 @@
|
|
|
1
|
+
import { FacadeChatSDK } from "../../../common/facades/FacadeChatSDK";
|
|
2
|
+
import { BroadcastService } from "@microsoft/omnichannel-chat-components";
|
|
3
|
+
export declare const customEventCallback: (facadeChatSDK: FacadeChatSDK) => (event: object) => void;
|
|
4
|
+
export declare const subscribeToSendCustomEvent: (broadcastService: typeof BroadcastService, facadeChatSDK: FacadeChatSDK, customEventCallback: (fackageSdK: FacadeChatSDK) => (event: object) => void) => void;
|
|
@@ -2,8 +2,10 @@ import { Activity, Attachment, Message, User } from "botframework-directlinejs";
|
|
|
2
2
|
import { Subscriber } from "rxjs/Subscriber";
|
|
3
3
|
export declare const customerUser: User;
|
|
4
4
|
export declare const botUser: User;
|
|
5
|
+
export declare const agentUser: User;
|
|
5
6
|
export declare const postEchoActivity: (activityObserver: Subscriber<Activity> | undefined, activity: Message, user: User, delay?: number) => void;
|
|
6
7
|
export declare const postBotMessageActivity: (activityObserver: Subscriber<Activity> | undefined, text: string, tags?: string, delay?: number) => void;
|
|
8
|
+
export declare const postAgentMessageActivity: (activityObserver: Subscriber<Activity> | undefined, text: string, tags?: string, delay?: number) => void;
|
|
7
9
|
export declare const postSystemMessageActivity: (activityObserver: Subscriber<Activity> | undefined, text: string, delay?: number) => void;
|
|
8
10
|
export declare const postBotTypingActivity: (activityObserver: Subscriber<Activity> | undefined, delay?: number) => void;
|
|
9
11
|
export declare const postBotAttachmentActivity: (activityObserver: Subscriber<Activity> | undefined, attachments?: Attachment[], delay?: number) => void;
|
|
@@ -0,0 +1,8 @@
|
|
|
1
|
+
/******
|
|
2
|
+
* CallActionMiddleware
|
|
3
|
+
*
|
|
4
|
+
* Intercepts custom call actions and handles tel: URL navigation
|
|
5
|
+
******/
|
|
6
|
+
import { IWebChatAction } from "../../../interfaces/IWebChatAction";
|
|
7
|
+
declare const createCallActionMiddleware: () => () => (next: any) => (action: IWebChatAction) => any;
|
|
8
|
+
export default createCallActionMiddleware;
|
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
/******
|
|
2
|
+
* CustomEventMiddleware
|
|
3
|
+
*
|
|
4
|
+
* This middleware is invoked when a custom event is received.
|
|
5
|
+
* The callback is then invoked to handle the custom event.
|
|
6
|
+
******/
|
|
7
|
+
import { IWebChatAction } from "../../../interfaces/IWebChatAction";
|
|
8
|
+
import { BroadcastService } from "@microsoft/omnichannel-chat-components";
|
|
9
|
+
export declare const isValidCustomEvent: (activity: {
|
|
10
|
+
channelData?: {
|
|
11
|
+
metadata?: {
|
|
12
|
+
customEvent?: string;
|
|
13
|
+
customEventName?: string;
|
|
14
|
+
customEventValue?: unknown;
|
|
15
|
+
};
|
|
16
|
+
};
|
|
17
|
+
from?: {
|
|
18
|
+
role: string;
|
|
19
|
+
};
|
|
20
|
+
}) => boolean;
|
|
21
|
+
declare const createCustomEventMiddleware: (broadcastservice: typeof BroadcastService) => () => (next: (action: IWebChatAction) => void) => (action: IWebChatAction) => void;
|
|
22
|
+
export default createCustomEventMiddleware;
|
|
@@ -0,0 +1,5 @@
|
|
|
1
|
+
import { IWebChatAction } from "../../../interfaces/IWebChatAction";
|
|
2
|
+
import { ILiveChatWidgetContext } from "../../../../../contexts/common/ILiveChatWidgetContext";
|
|
3
|
+
import { Dispatch } from "react";
|
|
4
|
+
import { ILiveChatWidgetAction } from "../../../../../contexts/common/ILiveChatWidgetAction";
|
|
5
|
+
export declare const createQueueOverflowMiddleware: (state: ILiveChatWidgetContext, dispatch: Dispatch<ILiveChatWidgetAction>) => () => (next: (action: IWebChatAction) => void) => (action: IWebChatAction) => void;
|
|
@@ -1,11 +1,11 @@
|
|
|
1
1
|
import { MessagePayload } from "./Constants";
|
|
2
2
|
export declare class FirstResponseLatencyTracker {
|
|
3
3
|
private isABotConversation;
|
|
4
|
-
private
|
|
5
|
-
private isEnded;
|
|
4
|
+
private isTracking;
|
|
6
5
|
private startTrackingMessage?;
|
|
7
6
|
private stopTrackingMessage?;
|
|
8
7
|
private isReady;
|
|
8
|
+
private trackingTimeoutId?;
|
|
9
9
|
constructor();
|
|
10
10
|
private createTrackingMessage;
|
|
11
11
|
private startTracking;
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@microsoft/omnichannel-chat-widget",
|
|
3
|
-
"version": "1.8.
|
|
3
|
+
"version": "1.8.3-main.38c88a7",
|
|
4
4
|
"description": "Microsoft Omnichannel Chat Widget",
|
|
5
5
|
"main": "lib/cjs/index.js",
|
|
6
6
|
"types": "lib/types/index.d.ts",
|
|
@@ -86,8 +86,8 @@
|
|
|
86
86
|
"dependencies": {
|
|
87
87
|
"@azure/core-tracing": "^1.2.0",
|
|
88
88
|
"@microsoft/applicationinsights-web": "^3.3.6",
|
|
89
|
-
"@microsoft/omnichannel-chat-components": "1.1.
|
|
90
|
-
"@microsoft/omnichannel-chat-sdk": "^1.11.
|
|
89
|
+
"@microsoft/omnichannel-chat-components": "1.1.13",
|
|
90
|
+
"@microsoft/omnichannel-chat-sdk": "^1.11.6",
|
|
91
91
|
"@opentelemetry/api": "^1.9.0",
|
|
92
92
|
"abort-controller": "^3",
|
|
93
93
|
"abort-controller-es5": "^2.0.1",
|