@webex/contact-center 0.0.0-next.1

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.
Files changed (177) hide show
  1. package/README.md +81 -0
  2. package/__mocks__/workerMock.js +15 -0
  3. package/babel.config.js +15 -0
  4. package/dist/cc.js +1416 -0
  5. package/dist/cc.js.map +1 -0
  6. package/dist/config.js +72 -0
  7. package/dist/config.js.map +1 -0
  8. package/dist/constants.js +58 -0
  9. package/dist/constants.js.map +1 -0
  10. package/dist/index.js +142 -0
  11. package/dist/index.js.map +1 -0
  12. package/dist/logger-proxy.js +115 -0
  13. package/dist/logger-proxy.js.map +1 -0
  14. package/dist/metrics/MetricsManager.js +474 -0
  15. package/dist/metrics/MetricsManager.js.map +1 -0
  16. package/dist/metrics/behavioral-events.js +322 -0
  17. package/dist/metrics/behavioral-events.js.map +1 -0
  18. package/dist/metrics/constants.js +134 -0
  19. package/dist/metrics/constants.js.map +1 -0
  20. package/dist/services/WebCallingService.js +323 -0
  21. package/dist/services/WebCallingService.js.map +1 -0
  22. package/dist/services/agent/index.js +177 -0
  23. package/dist/services/agent/index.js.map +1 -0
  24. package/dist/services/agent/types.js +137 -0
  25. package/dist/services/agent/types.js.map +1 -0
  26. package/dist/services/config/Util.js +203 -0
  27. package/dist/services/config/Util.js.map +1 -0
  28. package/dist/services/config/constants.js +221 -0
  29. package/dist/services/config/constants.js.map +1 -0
  30. package/dist/services/config/index.js +607 -0
  31. package/dist/services/config/index.js.map +1 -0
  32. package/dist/services/config/types.js +334 -0
  33. package/dist/services/config/types.js.map +1 -0
  34. package/dist/services/constants.js +117 -0
  35. package/dist/services/constants.js.map +1 -0
  36. package/dist/services/core/Err.js +43 -0
  37. package/dist/services/core/Err.js.map +1 -0
  38. package/dist/services/core/GlobalTypes.js +6 -0
  39. package/dist/services/core/GlobalTypes.js.map +1 -0
  40. package/dist/services/core/Utils.js +126 -0
  41. package/dist/services/core/Utils.js.map +1 -0
  42. package/dist/services/core/WebexRequest.js +96 -0
  43. package/dist/services/core/WebexRequest.js.map +1 -0
  44. package/dist/services/core/aqm-reqs.js +246 -0
  45. package/dist/services/core/aqm-reqs.js.map +1 -0
  46. package/dist/services/core/constants.js +109 -0
  47. package/dist/services/core/constants.js.map +1 -0
  48. package/dist/services/core/types.js +6 -0
  49. package/dist/services/core/types.js.map +1 -0
  50. package/dist/services/core/websocket/WebSocketManager.js +187 -0
  51. package/dist/services/core/websocket/WebSocketManager.js.map +1 -0
  52. package/dist/services/core/websocket/connection-service.js +111 -0
  53. package/dist/services/core/websocket/connection-service.js.map +1 -0
  54. package/dist/services/core/websocket/keepalive.worker.js +94 -0
  55. package/dist/services/core/websocket/keepalive.worker.js.map +1 -0
  56. package/dist/services/core/websocket/types.js +6 -0
  57. package/dist/services/core/websocket/types.js.map +1 -0
  58. package/dist/services/index.js +78 -0
  59. package/dist/services/index.js.map +1 -0
  60. package/dist/services/task/AutoWrapup.js +88 -0
  61. package/dist/services/task/AutoWrapup.js.map +1 -0
  62. package/dist/services/task/TaskManager.js +369 -0
  63. package/dist/services/task/TaskManager.js.map +1 -0
  64. package/dist/services/task/constants.js +58 -0
  65. package/dist/services/task/constants.js.map +1 -0
  66. package/dist/services/task/contact.js +464 -0
  67. package/dist/services/task/contact.js.map +1 -0
  68. package/dist/services/task/dialer.js +60 -0
  69. package/dist/services/task/dialer.js.map +1 -0
  70. package/dist/services/task/index.js +1188 -0
  71. package/dist/services/task/index.js.map +1 -0
  72. package/dist/services/task/types.js +214 -0
  73. package/dist/services/task/types.js.map +1 -0
  74. package/dist/types/cc.d.ts +676 -0
  75. package/dist/types/config.d.ts +66 -0
  76. package/dist/types/constants.d.ts +45 -0
  77. package/dist/types/index.d.ts +178 -0
  78. package/dist/types/logger-proxy.d.ts +71 -0
  79. package/dist/types/metrics/MetricsManager.d.ts +223 -0
  80. package/dist/types/metrics/behavioral-events.d.ts +29 -0
  81. package/dist/types/metrics/constants.d.ts +127 -0
  82. package/dist/types/services/WebCallingService.d.ts +1 -0
  83. package/dist/types/services/agent/index.d.ts +46 -0
  84. package/dist/types/services/agent/types.d.ts +413 -0
  85. package/dist/types/services/config/Util.d.ts +19 -0
  86. package/dist/types/services/config/constants.d.ts +203 -0
  87. package/dist/types/services/config/index.d.ts +171 -0
  88. package/dist/types/services/config/types.d.ts +1113 -0
  89. package/dist/types/services/constants.d.ts +97 -0
  90. package/dist/types/services/core/Err.d.ts +119 -0
  91. package/dist/types/services/core/GlobalTypes.d.ts +33 -0
  92. package/dist/types/services/core/Utils.d.ts +36 -0
  93. package/dist/types/services/core/WebexRequest.d.ts +22 -0
  94. package/dist/types/services/core/aqm-reqs.d.ts +16 -0
  95. package/dist/types/services/core/constants.d.ts +85 -0
  96. package/dist/types/services/core/types.d.ts +47 -0
  97. package/dist/types/services/core/websocket/WebSocketManager.d.ts +34 -0
  98. package/dist/types/services/core/websocket/connection-service.d.ts +27 -0
  99. package/dist/types/services/core/websocket/keepalive.worker.d.ts +2 -0
  100. package/dist/types/services/core/websocket/types.d.ts +37 -0
  101. package/dist/types/services/index.d.ts +52 -0
  102. package/dist/types/services/task/AutoWrapup.d.ts +40 -0
  103. package/dist/types/services/task/TaskManager.d.ts +1 -0
  104. package/dist/types/services/task/constants.d.ts +46 -0
  105. package/dist/types/services/task/contact.d.ts +59 -0
  106. package/dist/types/services/task/dialer.d.ts +28 -0
  107. package/dist/types/services/task/index.d.ts +569 -0
  108. package/dist/types/services/task/types.d.ts +1041 -0
  109. package/dist/types/types.d.ts +452 -0
  110. package/dist/types/webex-config.d.ts +53 -0
  111. package/dist/types/webex.d.ts +7 -0
  112. package/dist/types.js +292 -0
  113. package/dist/types.js.map +1 -0
  114. package/dist/webex-config.js +60 -0
  115. package/dist/webex-config.js.map +1 -0
  116. package/dist/webex.js +99 -0
  117. package/dist/webex.js.map +1 -0
  118. package/jest.config.js +45 -0
  119. package/package.json +83 -0
  120. package/src/cc.ts +1618 -0
  121. package/src/config.ts +65 -0
  122. package/src/constants.ts +51 -0
  123. package/src/index.ts +220 -0
  124. package/src/logger-proxy.ts +110 -0
  125. package/src/metrics/MetricsManager.ts +512 -0
  126. package/src/metrics/behavioral-events.ts +332 -0
  127. package/src/metrics/constants.ts +135 -0
  128. package/src/services/WebCallingService.ts +351 -0
  129. package/src/services/agent/index.ts +149 -0
  130. package/src/services/agent/types.ts +440 -0
  131. package/src/services/config/Util.ts +261 -0
  132. package/src/services/config/constants.ts +249 -0
  133. package/src/services/config/index.ts +743 -0
  134. package/src/services/config/types.ts +1117 -0
  135. package/src/services/constants.ts +111 -0
  136. package/src/services/core/Err.ts +126 -0
  137. package/src/services/core/GlobalTypes.ts +34 -0
  138. package/src/services/core/Utils.ts +132 -0
  139. package/src/services/core/WebexRequest.ts +103 -0
  140. package/src/services/core/aqm-reqs.ts +272 -0
  141. package/src/services/core/constants.ts +106 -0
  142. package/src/services/core/types.ts +48 -0
  143. package/src/services/core/websocket/WebSocketManager.ts +196 -0
  144. package/src/services/core/websocket/connection-service.ts +142 -0
  145. package/src/services/core/websocket/keepalive.worker.js +88 -0
  146. package/src/services/core/websocket/types.ts +40 -0
  147. package/src/services/index.ts +71 -0
  148. package/src/services/task/AutoWrapup.ts +86 -0
  149. package/src/services/task/TaskManager.ts +420 -0
  150. package/src/services/task/constants.ts +52 -0
  151. package/src/services/task/contact.ts +429 -0
  152. package/src/services/task/dialer.ts +52 -0
  153. package/src/services/task/index.ts +1375 -0
  154. package/src/services/task/types.ts +1113 -0
  155. package/src/types.ts +639 -0
  156. package/src/webex-config.ts +54 -0
  157. package/src/webex.js +96 -0
  158. package/test/unit/spec/cc.ts +1985 -0
  159. package/test/unit/spec/metrics/MetricsManager.ts +491 -0
  160. package/test/unit/spec/metrics/behavioral-events.ts +102 -0
  161. package/test/unit/spec/services/WebCallingService.ts +416 -0
  162. package/test/unit/spec/services/agent/index.ts +65 -0
  163. package/test/unit/spec/services/config/index.ts +1035 -0
  164. package/test/unit/spec/services/core/Utils.ts +279 -0
  165. package/test/unit/spec/services/core/WebexRequest.ts +144 -0
  166. package/test/unit/spec/services/core/aqm-reqs.ts +570 -0
  167. package/test/unit/spec/services/core/websocket/WebSocketManager.ts +378 -0
  168. package/test/unit/spec/services/core/websocket/connection-service.ts +178 -0
  169. package/test/unit/spec/services/task/TaskManager.ts +1351 -0
  170. package/test/unit/spec/services/task/contact.ts +204 -0
  171. package/test/unit/spec/services/task/dialer.ts +157 -0
  172. package/test/unit/spec/services/task/index.ts +1474 -0
  173. package/tsconfig.json +6 -0
  174. package/typedoc.json +37 -0
  175. package/typedoc.md +240 -0
  176. package/umd/contact-center.min.js +3 -0
  177. package/umd/contact-center.min.js.map +1 -0
@@ -0,0 +1,512 @@
1
+ import {
2
+ EventPayload,
3
+ MetricEventAgent,
4
+ MetricEventProduct,
5
+ MetricEventVerb,
6
+ } from '@webex/internal-plugin-metrics/src/metrics.types';
7
+
8
+ import {WebexSDK} from '../types';
9
+ import {BehavioralEventTaxonomy, getEventTaxonomy} from './behavioral-events';
10
+ import LoggerProxy from '../logger-proxy';
11
+ import {METRIC_EVENT_NAMES} from './constants';
12
+ import {Failure} from '../services/core/GlobalTypes';
13
+ import {PRODUCT_NAME} from '../constants';
14
+
15
+ type BehavioralEvent = {
16
+ taxonomy: BehavioralEventTaxonomy;
17
+ payload: EventPayload;
18
+ };
19
+
20
+ type GenericEvent = {
21
+ name: string;
22
+ payload: EventPayload;
23
+ };
24
+
25
+ export type MetricsType = 'behavioral' | 'operational' | 'business';
26
+
27
+ const PRODUCT_NAME_UPPER = PRODUCT_NAME.toUpperCase();
28
+ /**
29
+ * @class MetricsManager
30
+ * @classdesc Manages the collection, batching, and submission of behavioral, operational, and business metrics for the Webex SDK.
31
+ * Implements a singleton pattern to ensure a single instance throughout the application lifecycle.
32
+ *
33
+ * @remarks
34
+ * This class is responsible for tracking, batching, and submitting various types of metric events.
35
+ * It also provides utility methods for extracting common tracking fields from AQM responses.
36
+ * @ignore
37
+ */
38
+ export default class MetricsManager {
39
+ /**
40
+ * The Webex SDK instance used for submitting metrics.
41
+ * @private
42
+ */
43
+ private webex: WebexSDK;
44
+
45
+ /**
46
+ * Stores currently running timed events.
47
+ * @private
48
+ */
49
+ private readonly runningEvents: Record<string, {startTime: number; keys: Set<string>}> = {};
50
+
51
+ /**
52
+ * Queue for pending behavioral events.
53
+ * @private
54
+ */
55
+ private pendingBehavioralEvents: BehavioralEvent[] = [];
56
+
57
+ /**
58
+ * Queue for pending operational events.
59
+ * @private
60
+ */
61
+ private pendingOperationalEvents: GenericEvent[] = [];
62
+
63
+ /**
64
+ * Queue for pending business events.
65
+ * @private
66
+ */
67
+ private pendingBusinessEvents: GenericEvent[] = [];
68
+
69
+ /**
70
+ * Indicates if the manager is ready to submit events.
71
+ * @private
72
+ */
73
+ private readyToSubmitEvents = false;
74
+
75
+ /**
76
+ * Lock to prevent concurrent submissions.
77
+ * @private
78
+ */
79
+ private submittingEvents = false; // Add a lock for submitting events
80
+
81
+ /**
82
+ * Singleton instance of MetricsManager.
83
+ * @private
84
+ */
85
+ private static instance: MetricsManager;
86
+
87
+ /**
88
+ * Flag to disable metrics collection.
89
+ * @private
90
+ */
91
+ private metricsDisabled = false; // TODO: SPARK-637285
92
+
93
+ /**
94
+ * Private constructor to enforce singleton pattern.
95
+ * @private
96
+ */
97
+ // eslint-disable-next-line no-useless-constructor
98
+ private constructor() {}
99
+
100
+ /**
101
+ * Marks the manager as ready to submit events and triggers submission.
102
+ * @private
103
+ */
104
+ private setReadyToSubmitEvents() {
105
+ this.readyToSubmitEvents = true;
106
+ this.submitPendingEvents();
107
+ }
108
+
109
+ /**
110
+ * Submits all pending events if not already submitting.
111
+ * @private
112
+ */
113
+ private async submitPendingEvents() {
114
+ if (this.submittingEvents) {
115
+ return;
116
+ }
117
+ this.submittingEvents = true;
118
+ try {
119
+ await this.submitPendingBehavioralEvents();
120
+ await this.submitPendingOperationalEvents();
121
+ await this.submitPendingBusinessEvents();
122
+ } finally {
123
+ this.submittingEvents = false;
124
+ }
125
+ }
126
+
127
+ /**
128
+ * Submits all pending behavioral events if ready.
129
+ * @private
130
+ */
131
+ private async submitPendingBehavioralEvents() {
132
+ if (this.pendingBehavioralEvents.length === 0) {
133
+ return;
134
+ }
135
+ if (this.readyToSubmitEvents) {
136
+ const eventsToSubmit = [...this.pendingBehavioralEvents];
137
+ this.pendingBehavioralEvents.length = 0;
138
+ eventsToSubmit.forEach((event) => {
139
+ this.webex.internal.newMetrics.submitBehavioralEvent({
140
+ product: event.taxonomy.product as MetricEventProduct,
141
+ agent: event.taxonomy.agent as MetricEventAgent,
142
+ target: event.taxonomy.target,
143
+ verb: event.taxonomy.verb as MetricEventVerb,
144
+ payload: event.payload,
145
+ });
146
+ });
147
+ }
148
+ }
149
+
150
+ /**
151
+ * Submits all pending operational events if ready.
152
+ * @private
153
+ */
154
+ private async submitPendingOperationalEvents() {
155
+ if (this.pendingOperationalEvents.length === 0) {
156
+ return;
157
+ }
158
+ if (this.readyToSubmitEvents) {
159
+ const eventsToSubmit = [...this.pendingOperationalEvents];
160
+ this.pendingOperationalEvents.length = 0;
161
+ eventsToSubmit.forEach((event) => {
162
+ this.webex.internal.newMetrics.submitOperationalEvent({
163
+ name: `${PRODUCT_NAME_UPPER}_${event.name}`,
164
+ payload: event.payload,
165
+ });
166
+ });
167
+ }
168
+ }
169
+
170
+ /**
171
+ * Submits all pending business events if ready.
172
+ * @private
173
+ */
174
+ private async submitPendingBusinessEvents() {
175
+ if (this.pendingBusinessEvents.length === 0) {
176
+ return;
177
+ }
178
+ if (this.readyToSubmitEvents) {
179
+ const eventsToSubmit = [...this.pendingBusinessEvents];
180
+ this.pendingBusinessEvents.length = 0;
181
+ eventsToSubmit.forEach((event) => {
182
+ this.webex.internal.newMetrics.submitBusinessEvent({
183
+ name: `${PRODUCT_NAME_UPPER}_${event.name}`,
184
+ payload: event.payload,
185
+ metadata: {
186
+ appType: PRODUCT_NAME,
187
+ },
188
+ });
189
+ });
190
+ }
191
+ }
192
+
193
+ /**
194
+ * Adds a duration property to the event payload if the event was timed.
195
+ * @param eventName - The name of the event.
196
+ * @param options - Optional event payload.
197
+ * @returns The event payload with duration if applicable.
198
+ * @private
199
+ */
200
+ private addDurationIfTimed(eventName: string, options?: EventPayload): EventPayload {
201
+ const durationKey = 'duration_ms';
202
+ for (const [genericKey, timing] of Object.entries(this.runningEvents)) {
203
+ if (timing.keys.has(eventName)) {
204
+ const startTime = timing.startTime;
205
+ // Remove all keys for this operation.
206
+ delete this.runningEvents[genericKey];
207
+ options = options || {};
208
+ options[durationKey] = Date.now() - startTime;
209
+
210
+ return options;
211
+ }
212
+ }
213
+
214
+ return options || {};
215
+ }
216
+
217
+ /**
218
+ * Converts spaces in a string to underscores.
219
+ * @param str - The input string.
220
+ * @returns The string with spaces replaced by underscores.
221
+ * @public
222
+ * @example
223
+ * MetricsManager.spacesToUnderscore('my event name'); // 'my_event_name'
224
+ */
225
+ static spacesToUnderscore(str: string): string {
226
+ return str.replace(/ /g, '_');
227
+ }
228
+
229
+ /**
230
+ * Prepares the event payload by removing empty or undefined fields and adding common metadata.
231
+ * @param obj - The original event payload.
232
+ * @returns The cleaned and enriched event payload.
233
+ * @private
234
+ */
235
+ private static preparePayload(obj: EventPayload): EventPayload {
236
+ const payload: EventPayload = {};
237
+
238
+ Object.keys(obj).forEach((key) => {
239
+ if (
240
+ obj[key] !== undefined &&
241
+ obj[key] !== null &&
242
+ obj[key] !== '' &&
243
+ !Array.isArray(obj[key]) &&
244
+ !(typeof obj[key] === 'object' && Object.keys(obj[key]).length === 0)
245
+ ) {
246
+ payload[MetricsManager.spacesToUnderscore(key)] = obj[key];
247
+ }
248
+ });
249
+
250
+ if (typeof window === 'undefined') {
251
+ return payload;
252
+ }
253
+
254
+ const payloadWithCommonMetadata = {...payload};
255
+ payloadWithCommonMetadata.tabHidden = document.hidden;
256
+
257
+ return payloadWithCommonMetadata;
258
+ }
259
+
260
+ /**
261
+ * Checks if metrics collection is currently disabled.
262
+ * @returns True if metrics are disabled, false otherwise.
263
+ * @private
264
+ */
265
+ private isMetricsDisabled(): boolean {
266
+ // TODO: SPARK-637285 Need to return true if in development mode to avoid sending metrics to the server
267
+ return this.metricsDisabled;
268
+ }
269
+
270
+ /**
271
+ * Enables or disables metrics collection. Clears pending events if disabled.
272
+ * @param disabled - Whether to disable metrics.
273
+ * @public
274
+ * @example
275
+ * MetricsManager.getInstance().setMetricsDisabled(true);
276
+ */
277
+ public setMetricsDisabled(disabled: boolean) {
278
+ this.metricsDisabled = disabled;
279
+ if (disabled) {
280
+ this.clearPendingEvents();
281
+ }
282
+ }
283
+
284
+ /**
285
+ * Clears all pending events from the queues.
286
+ * @private
287
+ */
288
+ private clearPendingEvents() {
289
+ this.pendingBehavioralEvents.length = 0;
290
+ this.pendingOperationalEvents.length = 0;
291
+ this.pendingBusinessEvents.length = 0;
292
+ }
293
+
294
+ /**
295
+ * Tracks a behavioral event and submits it if possible.
296
+ * @param name - The metric event name.
297
+ * @param options - Optional event payload.
298
+ * @public
299
+ * @example
300
+ * MetricsManager.getInstance().trackBehavioralEvent('AGENT_LOGIN', {agentId: '123'});
301
+ */
302
+ public trackBehavioralEvent(name: METRIC_EVENT_NAMES, options?: EventPayload) {
303
+ if (this.isMetricsDisabled()) {
304
+ return;
305
+ }
306
+
307
+ const taxonomy = getEventTaxonomy(name);
308
+
309
+ const payload = MetricsManager.preparePayload(this.addDurationIfTimed(name, options));
310
+
311
+ this.pendingBehavioralEvents.push({taxonomy, payload});
312
+ this.submitPendingBehavioralEvents();
313
+ }
314
+
315
+ /**
316
+ * Tracks an operational event and submits it if possible.
317
+ * @param name - The metric event name.
318
+ * @param options - Optional event payload.
319
+ * @public
320
+ * @example
321
+ * MetricsManager.getInstance().trackOperationalEvent('AGENT_LOGOUT', {agentId: '123'});
322
+ */
323
+ public trackOperationalEvent(name: METRIC_EVENT_NAMES, options?: EventPayload) {
324
+ if (this.isMetricsDisabled()) {
325
+ return;
326
+ }
327
+
328
+ const payload = this.addDurationIfTimed(name, options);
329
+ this.pendingOperationalEvents.push({
330
+ name: MetricsManager.spacesToUnderscore(name).toUpperCase(),
331
+ payload: MetricsManager.preparePayload(payload),
332
+ });
333
+ this.submitPendingOperationalEvents();
334
+ }
335
+
336
+ /**
337
+ * Tracks a business event and submits it if possible.
338
+ * @param name - The metric event name.
339
+ * @param options - Optional event payload.
340
+ * @public
341
+ * @example
342
+ * MetricsManager.getInstance().trackBusinessEvent('AGENT_TRANSFER', {agentId: '123'});
343
+ */
344
+ public trackBusinessEvent(name: METRIC_EVENT_NAMES, options?: EventPayload) {
345
+ if (this.isMetricsDisabled()) {
346
+ return;
347
+ }
348
+
349
+ const payload = this.addDurationIfTimed(name, options);
350
+ this.pendingBusinessEvents.push({
351
+ name: MetricsManager.spacesToUnderscore(name).toUpperCase(),
352
+ payload: MetricsManager.preparePayload(payload),
353
+ });
354
+ this.submitPendingBusinessEvents();
355
+ }
356
+
357
+ /**
358
+ * Tracks an event across one or more metric services.
359
+ * @param name - The metric event name.
360
+ * @param payload - Optional event payload.
361
+ * @param metricServices - Array of metric types to track (default: ['behavioral']).
362
+ * @public
363
+ * @example
364
+ * MetricsManager.getInstance().trackEvent('AGENT_LOGIN', {agentId: '123'}, ['behavioral', 'operational']);
365
+ */
366
+ public trackEvent(
367
+ name: METRIC_EVENT_NAMES,
368
+ payload?: EventPayload,
369
+ metricServices: MetricsType[] = ['behavioral']
370
+ ) {
371
+ if (this.isMetricsDisabled()) {
372
+ return;
373
+ }
374
+
375
+ for (const metricService of metricServices) {
376
+ switch (metricService) {
377
+ case 'behavioral':
378
+ this.trackBehavioralEvent(name, payload);
379
+ break;
380
+ case 'operational':
381
+ this.trackOperationalEvent(name, payload);
382
+ break;
383
+ case 'business':
384
+ this.trackBusinessEvent(name, payload);
385
+ break;
386
+ default:
387
+ LoggerProxy.error(`[MetricsManager] Invalid metric type: ${metricService}`);
388
+ }
389
+ }
390
+ }
391
+
392
+ /**
393
+ * Starts timing for one or more event keys.
394
+ * @param keys - A string or array of strings representing event keys.
395
+ * @public
396
+ * @example
397
+ * MetricsManager.getInstance().timeEvent('AGENT_LOGIN');
398
+ * MetricsManager.getInstance().timeEvent(['AGENT_LOGIN', 'AGENT_LOGOUT']);
399
+ */
400
+ public timeEvent(keys: string | string[]) {
401
+ if (this.isMetricsDisabled()) {
402
+ return;
403
+ }
404
+ const keyArray = Array.isArray(keys) ? keys : [keys];
405
+ // Use the first key as the tracking key.
406
+ if (keyArray.length === 0) {
407
+ LoggerProxy.error('[MetricsManager] No keys provided for timeEvent');
408
+
409
+ return;
410
+ }
411
+ const genericKey = keyArray[0];
412
+ this.runningEvents[genericKey] = {startTime: Date.now(), keys: new Set(keyArray)};
413
+ }
414
+
415
+ /**
416
+ * Sets the Webex SDK instance and marks the manager as ready when the SDK is ready.
417
+ * @param webex - The Webex SDK instance.
418
+ * @private
419
+ */
420
+ private setWebex(webex: WebexSDK) {
421
+ this.webex = webex;
422
+ if (this.webex.ready) {
423
+ this.setReadyToSubmitEvents();
424
+ }
425
+ this.webex.once('ready', () => {
426
+ this.setReadyToSubmitEvents();
427
+ });
428
+ }
429
+
430
+ /**
431
+ * Returns the singleton instance of MetricsManager, initializing it if necessary.
432
+ * @param options - Optional object containing the Webex SDK instance.
433
+ * @returns The singleton MetricsManager instance.
434
+ * @public
435
+ * @example
436
+ * const metrics = MetricsManager.getInstance({webex});
437
+ */
438
+ public static getInstance(options?: {webex: WebexSDK}): MetricsManager {
439
+ if (!MetricsManager.instance) {
440
+ MetricsManager.instance = new MetricsManager();
441
+ }
442
+
443
+ if (!MetricsManager.instance.webex && options && options.webex) {
444
+ MetricsManager.instance.setWebex(options.webex);
445
+ }
446
+
447
+ return MetricsManager.instance;
448
+ }
449
+
450
+ /**
451
+ * Resets the singleton instance of MetricsManager. Useful for testing.
452
+ * @public
453
+ * @example
454
+ * MetricsManager.resetInstance();
455
+ */
456
+ public static resetInstance() {
457
+ MetricsManager.instance = undefined;
458
+ }
459
+
460
+ /**
461
+ * Extracts common tracking fields from an AQM response object.
462
+ * @param response - The AQM response object.
463
+ * @returns An object containing common tracking fields.
464
+ * @public
465
+ * @example
466
+ * const fields = MetricsManager.getCommonTrackingFieldForAQMResponse(response);
467
+ */
468
+ public static getCommonTrackingFieldForAQMResponse(response: any): Record<string, any> {
469
+ // This method is used to extract common tracking fields from the AQM response
470
+ // and return them as an object. The fields are extracted from the response
471
+ // object and its data property.
472
+ const fields = {
473
+ agentId: response?.data?.agentId || response?.agentId,
474
+ agentSessionId: response?.data?.agentSessionId || response?.agentSessionId,
475
+ teamId: response?.teamId ?? response?.data?.teamId ?? undefined,
476
+ siteId: response?.data?.siteId || response?.siteId,
477
+ orgId: response?.data?.orgId || response?.orgId,
478
+ eventType: response?.type,
479
+ trackingId: response?.data?.trackingId,
480
+ notifTrackingId: response?.trackingId,
481
+ };
482
+
483
+ return fields;
484
+ }
485
+
486
+ /**
487
+ * Extracts common tracking fields from an AQM failure response object.
488
+ * @param failureResponse - The AQM failure response object.
489
+ * @returns An object containing common tracking fields for failures.
490
+ * @public
491
+ * @example
492
+ * const fields = MetricsManager.getCommonTrackingFieldForAQMResponseFailed(failureResponse);
493
+ */
494
+ public static getCommonTrackingFieldForAQMResponseFailed(
495
+ failureResponse: Failure
496
+ ): Record<string, any> {
497
+ // This method is used to extract common tracking fields from the AQM response failure
498
+ // and return them as an object. The fields are extracted from the response
499
+ // object and its data property.
500
+ const fields = {
501
+ agentId: failureResponse?.data?.agentId,
502
+ trackingId: failureResponse?.trackingId,
503
+ notifTrackingId: failureResponse?.trackingId,
504
+ orgId: failureResponse?.orgId,
505
+ failureType: failureResponse?.type,
506
+ failureReason: failureResponse?.data?.reason,
507
+ reasonCode: failureResponse?.data?.reasonCode,
508
+ };
509
+
510
+ return fields;
511
+ }
512
+ }