@webex/contact-center 3.12.0-next.73 → 3.12.0-next.74

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 (188) hide show
  1. package/AGENTS.md +438 -0
  2. package/ai-docs/README.md +131 -0
  3. package/ai-docs/RULES.md +455 -0
  4. package/ai-docs/patterns/event-driven-patterns.md +485 -0
  5. package/ai-docs/patterns/testing-patterns.md +480 -0
  6. package/ai-docs/patterns/typescript-patterns.md +365 -0
  7. package/ai-docs/templates/README.md +102 -0
  8. package/ai-docs/templates/documentation/create-agents-md.md +240 -0
  9. package/ai-docs/templates/documentation/create-architecture-md.md +295 -0
  10. package/ai-docs/templates/existing-service/bug-fix.md +254 -0
  11. package/ai-docs/templates/existing-service/feature-enhancement.md +450 -0
  12. package/ai-docs/templates/new-method/00-master.md +80 -0
  13. package/ai-docs/templates/new-method/01-requirements.md +232 -0
  14. package/ai-docs/templates/new-method/02-implementation.md +295 -0
  15. package/ai-docs/templates/new-method/03-tests.md +201 -0
  16. package/ai-docs/templates/new-method/04-validation.md +141 -0
  17. package/ai-docs/templates/new-service/00-master.md +109 -0
  18. package/ai-docs/templates/new-service/01-pre-questions.md +159 -0
  19. package/ai-docs/templates/new-service/02-code-generation.md +346 -0
  20. package/ai-docs/templates/new-service/03-integration.md +178 -0
  21. package/ai-docs/templates/new-service/04-test-generation.md +205 -0
  22. package/ai-docs/templates/new-service/05-validation.md +145 -0
  23. package/dist/cc.js +53 -38
  24. package/dist/cc.js.map +1 -1
  25. package/dist/config.js +6 -0
  26. package/dist/config.js.map +1 -1
  27. package/dist/constants.js +14 -1
  28. package/dist/constants.js.map +1 -1
  29. package/dist/index.js +13 -5
  30. package/dist/index.js.map +1 -1
  31. package/dist/metrics/behavioral-events.js +26 -0
  32. package/dist/metrics/behavioral-events.js.map +1 -1
  33. package/dist/metrics/constants.js +9 -3
  34. package/dist/metrics/constants.js.map +1 -1
  35. package/dist/services/ApiAiAssistant.js +74 -3
  36. package/dist/services/ApiAiAssistant.js.map +1 -1
  37. package/dist/services/config/Util.js +2 -2
  38. package/dist/services/config/Util.js.map +1 -1
  39. package/dist/services/config/types.js +25 -9
  40. package/dist/services/config/types.js.map +1 -1
  41. package/dist/services/core/Utils.js +74 -27
  42. package/dist/services/core/Utils.js.map +1 -1
  43. package/dist/services/core/websocket/WebSocketManager.js +2 -1
  44. package/dist/services/core/websocket/WebSocketManager.js.map +1 -1
  45. package/dist/services/core/websocket/types.js.map +1 -1
  46. package/dist/services/index.js +1 -1
  47. package/dist/services/index.js.map +1 -1
  48. package/dist/services/task/Task.js +688 -0
  49. package/dist/services/task/Task.js.map +1 -0
  50. package/dist/services/task/TaskFactory.js +45 -0
  51. package/dist/services/task/TaskFactory.js.map +1 -0
  52. package/dist/services/task/TaskManager.js +725 -612
  53. package/dist/services/task/TaskManager.js.map +1 -1
  54. package/dist/services/task/TaskUtils.js +162 -26
  55. package/dist/services/task/TaskUtils.js.map +1 -1
  56. package/dist/services/task/constants.js +6 -1
  57. package/dist/services/task/constants.js.map +1 -1
  58. package/dist/services/task/digital/Digital.js +77 -0
  59. package/dist/services/task/digital/Digital.js.map +1 -0
  60. package/dist/services/task/state-machine/TaskStateMachine.js +837 -0
  61. package/dist/services/task/state-machine/TaskStateMachine.js.map +1 -0
  62. package/dist/services/task/state-machine/actions.js +543 -0
  63. package/dist/services/task/state-machine/actions.js.map +1 -0
  64. package/dist/services/task/state-machine/constants.js +161 -0
  65. package/dist/services/task/state-machine/constants.js.map +1 -0
  66. package/dist/services/task/state-machine/guards.js +340 -0
  67. package/dist/services/task/state-machine/guards.js.map +1 -0
  68. package/dist/services/task/state-machine/index.js +53 -0
  69. package/dist/services/task/state-machine/index.js.map +1 -0
  70. package/dist/services/task/state-machine/types.js +54 -0
  71. package/dist/services/task/state-machine/types.js.map +1 -0
  72. package/dist/services/task/state-machine/uiControlsComputer.js +553 -0
  73. package/dist/services/task/state-machine/uiControlsComputer.js.map +1 -0
  74. package/dist/services/task/taskDataNormalizer.js +99 -0
  75. package/dist/services/task/taskDataNormalizer.js.map +1 -0
  76. package/dist/services/task/types.js +168 -16
  77. package/dist/services/task/types.js.map +1 -1
  78. package/dist/services/task/voice/Voice.js +1042 -0
  79. package/dist/services/task/voice/Voice.js.map +1 -0
  80. package/dist/services/task/voice/WebRTC.js +149 -0
  81. package/dist/services/task/voice/WebRTC.js.map +1 -0
  82. package/dist/types/cc.d.ts +19 -18
  83. package/dist/types/config.d.ts +6 -0
  84. package/dist/types/constants.d.ts +14 -1
  85. package/dist/types/index.d.ts +11 -5
  86. package/dist/types/metrics/constants.d.ts +7 -1
  87. package/dist/types/services/ApiAiAssistant.d.ts +11 -3
  88. package/dist/types/services/config/types.d.ts +113 -9
  89. package/dist/types/services/core/Utils.d.ts +23 -10
  90. package/dist/types/services/core/websocket/WebSocketManager.d.ts +1 -0
  91. package/dist/types/services/core/websocket/types.d.ts +1 -1
  92. package/dist/types/services/index.d.ts +1 -1
  93. package/dist/types/services/task/Task.d.ts +157 -0
  94. package/dist/types/services/task/TaskFactory.d.ts +12 -0
  95. package/dist/types/services/task/TaskUtils.d.ts +46 -2
  96. package/dist/types/services/task/constants.d.ts +5 -0
  97. package/dist/types/services/task/digital/Digital.d.ts +22 -0
  98. package/dist/types/services/task/state-machine/TaskStateMachine.d.ts +1144 -0
  99. package/dist/types/services/task/state-machine/actions.d.ts +10 -0
  100. package/dist/types/services/task/state-machine/constants.d.ts +107 -0
  101. package/dist/types/services/task/state-machine/guards.d.ts +90 -0
  102. package/dist/types/services/task/state-machine/index.d.ts +13 -0
  103. package/dist/types/services/task/state-machine/types.d.ts +267 -0
  104. package/dist/types/services/task/state-machine/uiControlsComputer.d.ts +9 -0
  105. package/dist/types/services/task/taskDataNormalizer.d.ts +10 -0
  106. package/dist/types/services/task/types.d.ts +551 -78
  107. package/dist/types/services/task/voice/Voice.d.ts +184 -0
  108. package/dist/types/services/task/voice/WebRTC.d.ts +53 -0
  109. package/dist/types/types.d.ts +92 -0
  110. package/dist/types/webex.d.ts +1 -0
  111. package/dist/types.js +85 -0
  112. package/dist/types.js.map +1 -1
  113. package/dist/webex.js +14 -2
  114. package/dist/webex.js.map +1 -1
  115. package/package.json +15 -12
  116. package/src/cc.ts +63 -43
  117. package/src/config.ts +6 -0
  118. package/src/constants.ts +14 -1
  119. package/src/index.ts +14 -5
  120. package/src/metrics/ai-docs/AGENTS.md +348 -0
  121. package/src/metrics/ai-docs/ARCHITECTURE.md +336 -0
  122. package/src/metrics/behavioral-events.ts +28 -0
  123. package/src/metrics/constants.ts +9 -4
  124. package/src/services/ApiAiAssistant.ts +104 -3
  125. package/src/services/agent/ai-docs/AGENTS.md +238 -0
  126. package/src/services/agent/ai-docs/ARCHITECTURE.md +302 -0
  127. package/src/services/ai-docs/AGENTS.md +384 -0
  128. package/src/services/config/Util.ts +2 -2
  129. package/src/services/config/ai-docs/AGENTS.md +253 -0
  130. package/src/services/config/ai-docs/ARCHITECTURE.md +424 -0
  131. package/src/services/config/types.ts +116 -10
  132. package/src/services/core/Utils.ts +85 -34
  133. package/src/services/core/ai-docs/AGENTS.md +379 -0
  134. package/src/services/core/ai-docs/ARCHITECTURE.md +696 -0
  135. package/src/services/core/websocket/WebSocketManager.ts +2 -0
  136. package/src/services/core/websocket/types.ts +1 -1
  137. package/src/services/index.ts +1 -1
  138. package/src/services/task/Task.ts +837 -0
  139. package/src/services/task/TaskFactory.ts +55 -0
  140. package/src/services/task/TaskManager.ts +738 -697
  141. package/src/services/task/TaskUtils.ts +205 -25
  142. package/src/services/task/ai-docs/AGENTS.md +455 -0
  143. package/src/services/task/ai-docs/ARCHITECTURE.md +585 -0
  144. package/src/services/task/constants.ts +5 -0
  145. package/src/services/task/digital/Digital.ts +95 -0
  146. package/src/services/task/state-machine/TaskStateMachine.ts +1077 -0
  147. package/src/services/task/state-machine/actions.ts +685 -0
  148. package/src/services/task/state-machine/ai-docs/AGENTS.md +495 -0
  149. package/src/services/task/state-machine/ai-docs/ARCHITECTURE.md +1135 -0
  150. package/src/services/task/state-machine/constants.ts +172 -0
  151. package/src/services/task/state-machine/guards.ts +406 -0
  152. package/src/services/task/state-machine/index.ts +28 -0
  153. package/src/services/task/state-machine/types.ts +241 -0
  154. package/src/services/task/state-machine/uiControlsComputer.ts +867 -0
  155. package/src/services/task/taskDataNormalizer.ts +137 -0
  156. package/src/services/task/types.ts +654 -85
  157. package/src/services/task/voice/Voice.ts +1267 -0
  158. package/src/services/task/voice/WebRTC.ts +187 -0
  159. package/src/types.ts +112 -1
  160. package/src/utils/AGENTS.md +276 -0
  161. package/src/webex.js +2 -0
  162. package/test/unit/spec/cc.ts +133 -3
  163. package/test/unit/spec/logger-proxy.ts +70 -0
  164. package/test/unit/spec/services/ApiAiAssistant.ts +122 -17
  165. package/test/unit/spec/services/WebCallingService.ts +7 -1
  166. package/test/unit/spec/services/config/index.ts +27 -27
  167. package/test/unit/spec/services/core/Utils.ts +335 -1
  168. package/test/unit/spec/services/core/websocket/WebSocketManager.ts +66 -40
  169. package/test/unit/spec/services/task/AutoWrapup.ts +63 -0
  170. package/test/unit/spec/services/task/Task.ts +477 -0
  171. package/test/unit/spec/services/task/TaskFactory.ts +62 -0
  172. package/test/unit/spec/services/task/TaskManager.ts +821 -1936
  173. package/test/unit/spec/services/task/TaskUtils.ts +206 -0
  174. package/test/unit/spec/services/task/digital/Digital.ts +105 -0
  175. package/test/unit/spec/services/task/state-machine/TaskStateMachine.ts +1825 -0
  176. package/test/unit/spec/services/task/state-machine/guards.ts +479 -0
  177. package/test/unit/spec/services/task/state-machine/types.ts +18 -0
  178. package/test/unit/spec/services/task/state-machine/uiControlsComputer.ts +2020 -0
  179. package/test/unit/spec/services/task/taskTestUtils.ts +87 -0
  180. package/test/unit/spec/services/task/voice/Voice.ts +631 -0
  181. package/test/unit/spec/services/task/voice/WebRTC.ts +235 -0
  182. package/umd/contact-center.min.js +2 -2
  183. package/umd/contact-center.min.js.map +1 -1
  184. package/dist/services/task/index.js +0 -1530
  185. package/dist/services/task/index.js.map +0 -1
  186. package/dist/types/services/task/index.d.ts +0 -650
  187. package/src/services/task/index.ts +0 -1806
  188. package/test/unit/spec/services/task/index.ts +0 -2205
@@ -0,0 +1,688 @@
1
+ "use strict";
2
+
3
+ Object.defineProperty(exports, "__esModule", {
4
+ value: true
5
+ });
6
+ exports.default = void 0;
7
+ var _events = require("events");
8
+ var _xstate = require("xstate");
9
+ var _types = require("./types");
10
+ var _constants = require("./constants");
11
+ var _constants2 = require("../../constants");
12
+ var _Utils = require("../core/Utils");
13
+ var _MetricsManager = _interopRequireDefault(require("../../metrics/MetricsManager"));
14
+ var _constants3 = require("../../metrics/constants");
15
+ var _loggerProxy = _interopRequireDefault(require("../../logger-proxy"));
16
+ var _stateMachine = require("./state-machine");
17
+ var _uiControlsComputer = require("./state-machine/uiControlsComputer");
18
+ var _AutoWrapup = _interopRequireDefault(require("./AutoWrapup"));
19
+ function _interopRequireDefault(e) { return e && e.__esModule ? e : { default: e }; }
20
+ class Task extends _events.EventEmitter {
21
+ constructor(contact, data, uiControlConfig, wrapupData, agentId) {
22
+ super();
23
+ this.contact = contact;
24
+ this.data = data;
25
+ const channelType = uiControlConfig.channelType ?? Task.resolveChannelType(data);
26
+ // Include agentId in the config for ownership checks (transfer conference)
27
+ this.uiControlConfig = {
28
+ ...uiControlConfig,
29
+ channelType,
30
+ agentId
31
+ };
32
+ this.wrapupData = wrapupData;
33
+ this.agentId = agentId;
34
+ this.metricsManager = _MetricsManager.default.getInstance();
35
+ this.webCallMap = {};
36
+ this.currentUiControls = (0, _uiControlsComputer.getDefaultUIControls)();
37
+ this.initializeStateMachine();
38
+ this.setupAutoWrapupTimer();
39
+ }
40
+ static resolveChannelType(data) {
41
+ const mediaType = data?.interaction?.mediaType ?? _types.MEDIA_CHANNEL.TELEPHONY;
42
+ return mediaType === _types.MEDIA_CHANNEL.TELEPHONY ? _types.TASK_CHANNEL_TYPE.VOICE : _types.TASK_CHANNEL_TYPE.DIGITAL;
43
+ }
44
+
45
+ // Abstract methods that all child classes must implement
46
+
47
+ // Voice-specific methods with default implementations that throw errors
48
+ // Voice class will override these with actual implementations
49
+ async decline() {
50
+ this.unsupportedMethodError('decline');
51
+ }
52
+ async pauseRecording() {
53
+ this.unsupportedMethodError('pauseRecording');
54
+ }
55
+ async resumeRecording(resumeRecordingPayload) {
56
+ if (resumeRecordingPayload) {
57
+ // parameter intentionally unused
58
+ }
59
+ this.unsupportedMethodError('resumeRecording');
60
+ }
61
+ async consult(consultPayload) {
62
+ if (consultPayload) {
63
+ // parameter intentionally unused
64
+ }
65
+ this.unsupportedMethodError('consult');
66
+ }
67
+ async endConsult(consultEndPayload) {
68
+ if (consultEndPayload) {
69
+ // parameter intentionally unused
70
+ }
71
+ this.unsupportedMethodError('endConsult');
72
+ }
73
+ async consultTransfer(consultTransferPayload) {
74
+ if (consultTransferPayload) {
75
+ // parameter intentionally unused
76
+ }
77
+ this.unsupportedMethodError('consultTransfer');
78
+ }
79
+ async consultConference() {
80
+ this.unsupportedMethodError('consultConference');
81
+ }
82
+ async exitConference() {
83
+ this.unsupportedMethodError('exitConference');
84
+ }
85
+ async transferConference() {
86
+ this.unsupportedMethodError('transferConference');
87
+ }
88
+ async switchCall() {
89
+ this.unsupportedMethodError('switchCall');
90
+ }
91
+ async toggleMute() {
92
+ this.unsupportedMethodError('toggleMute');
93
+ }
94
+ unregisterWebCallListeners() {
95
+ // Default implementation - child classes can override
96
+ _loggerProxy.default.log('unregisterWebCallListeners called', {
97
+ module: _constants2.CC_FILE,
98
+ method: 'unregisterWebCallListeners',
99
+ interactionId: this.data?.interactionId
100
+ });
101
+ }
102
+
103
+ /**
104
+ * Cancel any in-progress auto wrap-up timer.
105
+ * Base implementation just clears the timer reference so subclasses inherit the behavior.
106
+ */
107
+ cancelAutoWrapupTimer() {
108
+ if (this.autoWrapup) {
109
+ this.autoWrapup.clear();
110
+ this.autoWrapup = undefined;
111
+ _loggerProxy.default.log('Auto wrap-up timer cancelled', {
112
+ module: _constants2.CC_FILE,
113
+ method: 'cancelAutoWrapupTimer',
114
+ interactionId: this.data?.interactionId
115
+ });
116
+ }
117
+ }
118
+
119
+ // Voice tasks use holdResume(), but provide separate methods for interface compliance
120
+ async hold() {
121
+ this.unsupportedMethodError('hold');
122
+ }
123
+ async resume() {
124
+ this.unsupportedMethodError('resume');
125
+ }
126
+ async holdResume() {
127
+ this.unsupportedMethodError('holdResume');
128
+ }
129
+
130
+ /**
131
+ * Latest UI controls derived from state machine state and context.
132
+ */
133
+ get uiControls() {
134
+ return this.currentUiControls;
135
+ }
136
+ updateUiControls(forceEmit = false) {
137
+ const nextControls = this.computeUIControls();
138
+ const shouldEmit = forceEmit || (0, _uiControlsComputer.haveUIControlsChanged)(this.currentUiControls, nextControls);
139
+ this.currentUiControls = nextControls;
140
+ if (shouldEmit) {
141
+ this.emit(_types.TASK_EVENTS.TASK_UI_CONTROLS_UPDATED, this.currentUiControls);
142
+ }
143
+ }
144
+
145
+ /**
146
+ * Initialize the state machine
147
+ */
148
+ initializeStateMachine() {
149
+ const machine = (0, _stateMachine.createTaskStateMachine)(this.uiControlConfig, {
150
+ actions: this.getStateMachineActionOverrides()
151
+ });
152
+ this.stateMachineService = (0, _xstate.createActor)(machine);
153
+ this.stateMachineService.subscribe(snapshot => {
154
+ const previousState = this.lastState;
155
+ const currentState = snapshot.value;
156
+ _loggerProxy.default.log(`State machine transition: ${previousState || 'N/A'} -> ${currentState}`, {
157
+ module: _constants2.CC_FILE,
158
+ method: 'onTransition',
159
+ // @ts-ignore - snapshot may include event detail depending on XState version
160
+ eventType: snapshot?.event?.type
161
+ });
162
+ this.lastState = currentState;
163
+ this.state = snapshot;
164
+ this.updateUiControls(previousState !== currentState);
165
+ });
166
+ this.stateMachineService.start();
167
+ this.updateUiControls(true);
168
+ }
169
+
170
+ /**
171
+ * Send an event to the state machine
172
+ */
173
+ sendStateMachineEvent(event) {
174
+ if (this.stateMachineService) {
175
+ _loggerProxy.default.log(`Sending state machine event: ${event?.type}`, {
176
+ module: _constants2.CC_FILE,
177
+ method: 'sendStateMachineEvent',
178
+ interactionId: this.data?.interactionId
179
+ });
180
+ this.stateMachineService.send(event);
181
+ }
182
+ }
183
+
184
+ /**
185
+ * Get the current state machine state
186
+ */
187
+ getCurrentState() {
188
+ return this.stateMachineService?.getSnapshot()?.value;
189
+ }
190
+
191
+ /**
192
+ * Compute UI controls based on current state machine state.
193
+ *
194
+ * @returns UI control states for all task actions
195
+ */
196
+ computeUIControls() {
197
+ const snapshot = this.stateMachineService?.getSnapshot?.();
198
+ if (!snapshot) {
199
+ return (0, _uiControlsComputer.getDefaultUIControls)();
200
+ }
201
+ const currentState = snapshot.value;
202
+ const context = snapshot.context;
203
+ const uiControls = (0, _uiControlsComputer.computeUIControls)(currentState, context, this.data);
204
+ return uiControls;
205
+ }
206
+
207
+ /**
208
+ * Stop the state machine service
209
+ */
210
+ stopStateMachine() {
211
+ if (this.stateMachineService) {
212
+ this.stateMachineService.stop();
213
+ this.stateMachineService = undefined;
214
+ }
215
+ }
216
+ static extractTaskDataFromEvent(event) {
217
+ if (!event || typeof event !== 'object') {
218
+ return undefined;
219
+ }
220
+ if ('taskData' in event) {
221
+ return event.taskData;
222
+ }
223
+ return undefined;
224
+ }
225
+ async autoAnswerIfNeeded() {
226
+ if (!this.data) {
227
+ return;
228
+ }
229
+ const autoAnswerSupported = this.uiControlConfig.channelType === _types.TASK_CHANNEL_TYPE.DIGITAL || this.uiControlConfig.voiceVariant === _types.VOICE_VARIANT.WEBRTC;
230
+ if (!autoAnswerSupported) {
231
+ return;
232
+ }
233
+ const shouldAutoAnswer = this.data.isAutoAnswering === true;
234
+ if (!shouldAutoAnswer) {
235
+ return;
236
+ }
237
+ _loggerProxy.default.info(`Auto-answering task`, {
238
+ module: _constants2.TASK_FILE,
239
+ method: 'autoAnswerIfNeeded',
240
+ interactionId: this.data.interactionId
241
+ });
242
+ try {
243
+ await this.accept();
244
+ _loggerProxy.default.info(`Task auto-answered successfully`, {
245
+ module: _constants2.TASK_FILE,
246
+ method: 'autoAnswerIfNeeded',
247
+ interactionId: this.data.interactionId
248
+ });
249
+ this.metricsManager.trackEvent(_constants3.METRIC_EVENT_NAMES.TASK_AUTO_ANSWER_SUCCESS, {
250
+ taskId: this.data.interactionId,
251
+ mediaType: this.data.interaction.mediaType,
252
+ isAutoAnswered: true
253
+ }, ['behavioral', 'operational']);
254
+ this.emit(_types.TASK_EVENTS.TASK_AUTO_ANSWERED, this);
255
+ } catch (error) {
256
+ this.updateTaskData({
257
+ ...this.data,
258
+ isAutoAnswering: false
259
+ });
260
+ _loggerProxy.default.error(`Failed to auto-answer task`, {
261
+ module: _constants2.TASK_FILE,
262
+ method: 'autoAnswerIfNeeded',
263
+ interactionId: this.data.interactionId,
264
+ error
265
+ });
266
+ this.metricsManager.trackEvent(_constants3.METRIC_EVENT_NAMES.TASK_AUTO_ANSWER_FAILED, {
267
+ taskId: this.data.interactionId,
268
+ mediaType: this.data.interaction.mediaType,
269
+ error: error?.message || 'Unknown error',
270
+ isAutoAnswered: false
271
+ }, ['behavioral', 'operational']);
272
+ }
273
+ }
274
+ updateTaskFromEvent(event) {
275
+ const taskData = Task.extractTaskDataFromEvent(event);
276
+ if (taskData) {
277
+ this.updateTaskData(taskData);
278
+ }
279
+ }
280
+ getStateMachineActionOverrides() {
281
+ return {
282
+ ...this.getCommonActionOverrides(),
283
+ ...this.getChannelSpecificActionOverrides()
284
+ };
285
+ }
286
+ getChannelSpecificActionOverrides() {
287
+ return {};
288
+ }
289
+ createEmitSelfAction(taskEvent, {
290
+ updateTaskData = false
291
+ } = {}) {
292
+ return ({
293
+ event
294
+ }) => {
295
+ if (updateTaskData) {
296
+ this.updateTaskFromEvent(event);
297
+ }
298
+ _loggerProxy.default.info(`Emitting task event ${taskEvent}`, {
299
+ module: _constants2.TASK_FILE,
300
+ method: 'emitTaskEvent',
301
+ interactionId: this.data?.interactionId
302
+ });
303
+ this.emit(taskEvent, this);
304
+ };
305
+ }
306
+ getCommonActionOverrides() {
307
+ return {
308
+ syncTaskDataFromEvent: ({
309
+ event
310
+ }) => {
311
+ this.updateTaskFromEvent(event);
312
+ },
313
+ emitTaskIncoming: this.createEmitSelfAction(_types.TASK_EVENTS.TASK_INCOMING, {
314
+ updateTaskData: true
315
+ }),
316
+ emitTaskCampaignPreviewReservation: this.createEmitSelfAction(_types.TASK_EVENTS.TASK_CAMPAIGN_PREVIEW_RESERVATION, {
317
+ updateTaskData: true
318
+ }),
319
+ emitTaskCampaignPreviewAcceptFailed: this.createEmitSelfAction(_types.TASK_EVENTS.TASK_CAMPAIGN_PREVIEW_ACCEPT_FAILED),
320
+ emitTaskCampaignPreviewSkipFailed: this.createEmitSelfAction(_types.TASK_EVENTS.TASK_CAMPAIGN_PREVIEW_SKIP_FAILED),
321
+ emitTaskCampaignPreviewRemoveFailed: this.createEmitSelfAction(_types.TASK_EVENTS.TASK_CAMPAIGN_PREVIEW_REMOVE_FAILED),
322
+ emitTaskHydrate: this.createEmitSelfAction(_types.TASK_EVENTS.TASK_HYDRATE, {
323
+ updateTaskData: true
324
+ }),
325
+ emitTaskOfferContact: this.createEmitSelfAction(_types.TASK_EVENTS.TASK_OFFER_CONTACT, {
326
+ updateTaskData: true
327
+ }),
328
+ emitTaskAssigned: ({
329
+ event
330
+ }) => {
331
+ this.updateTaskFromEvent(event);
332
+ this.emit(_types.TASK_EVENTS.TASK_ASSIGNED, this);
333
+ this.emit(_types.TASK_EVENTS.TASK_MULTI_LOGIN_HYDRATE, this);
334
+ },
335
+ emitTaskEnd: this.createEmitSelfAction(_types.TASK_EVENTS.TASK_END, {
336
+ updateTaskData: true
337
+ }),
338
+ emitTaskOfferConsult: this.createEmitSelfAction(_types.TASK_EVENTS.TASK_OFFER_CONSULT, {
339
+ updateTaskData: true
340
+ }),
341
+ emitTaskConsultCreated: this.createEmitSelfAction(_types.TASK_EVENTS.TASK_CONSULT_CREATED, {
342
+ updateTaskData: true
343
+ }),
344
+ emitTaskConsulting: ({
345
+ event
346
+ }) => {
347
+ this.updateTaskFromEvent(event);
348
+ if (this.data.isConsulted) {
349
+ this.emit(_types.TASK_EVENTS.TASK_CONSULT_ACCEPTED, this);
350
+ } else {
351
+ this.emit(_types.TASK_EVENTS.TASK_CONSULTING, this);
352
+ }
353
+ this.emit(_types.TASK_EVENTS.TASK_MULTI_LOGIN_HYDRATE, this);
354
+ },
355
+ emitTaskConsultAccepted: this.createEmitSelfAction(_types.TASK_EVENTS.TASK_CONSULT_ACCEPTED),
356
+ emitTaskConsultEnd: this.createEmitSelfAction(_types.TASK_EVENTS.TASK_CONSULT_END, {
357
+ updateTaskData: true
358
+ }),
359
+ emitTaskConsultQueueCancelled: this.createEmitSelfAction(_types.TASK_EVENTS.TASK_CONSULT_QUEUE_CANCELLED, {
360
+ updateTaskData: true
361
+ }),
362
+ emitTaskConsultQueueFailed: this.createEmitSelfAction(_types.TASK_EVENTS.TASK_CONSULT_QUEUE_FAILED, {
363
+ updateTaskData: true
364
+ }),
365
+ emitTaskReject: ({
366
+ event
367
+ }) => {
368
+ this.updateTaskFromEvent(event);
369
+ const reason = event && typeof event === 'object' && 'reason' in event ? event.reason : undefined;
370
+ this.emit(_types.TASK_EVENTS.TASK_REJECT, reason);
371
+ },
372
+ emitTaskWrapup: ({
373
+ event
374
+ }) => {
375
+ this.updateTaskFromEvent(event);
376
+ const shouldEmitWrapup = Boolean(this.data.wrapUpRequired);
377
+ if (!shouldEmitWrapup) {
378
+ _loggerProxy.default.info(`Skipping task:wrapup event - wrapUpRequired is false`, {
379
+ module: _constants2.TASK_FILE,
380
+ method: 'emitTaskEvent',
381
+ interactionId: this.data?.interactionId
382
+ });
383
+ return;
384
+ }
385
+ _loggerProxy.default.info(`Emitting task event ${_types.TASK_EVENTS.TASK_WRAPUP}`, {
386
+ module: _constants2.TASK_FILE,
387
+ method: 'emitTaskEvent',
388
+ interactionId: this.data?.interactionId
389
+ });
390
+ this.emit(_types.TASK_EVENTS.TASK_WRAPUP, this);
391
+ },
392
+ emitTaskWrappedup: this.createEmitSelfAction(_types.TASK_EVENTS.TASK_WRAPPEDUP, {
393
+ updateTaskData: true
394
+ }),
395
+ requestAutoAnswer: ({
396
+ event
397
+ }) => {
398
+ if (event) {
399
+ // parameter intentionally unused
400
+ }
401
+ this.autoAnswerIfNeeded();
402
+ },
403
+ requestCleanup: () => {
404
+ this.emit(_types.TASK_EVENTS.TASK_CLEANUP, this, {
405
+ removeFromCollection: false
406
+ });
407
+ },
408
+ cleanupResources: () => {
409
+ this.emit(_types.TASK_EVENTS.TASK_CLEANUP, this, {
410
+ removeFromCollection: true
411
+ });
412
+ }
413
+ };
414
+ }
415
+
416
+ /**
417
+ * Sets up the automatic wrap-up timer if wrap-up is required
418
+ */
419
+ setupAutoWrapupTimer() {
420
+ if (this.data.wrapUpRequired && !this.autoWrapup && this.wrapupData && this.wrapupData.wrapUpProps) {
421
+ const wrapUpProps = this.wrapupData.wrapUpProps;
422
+ if (!wrapUpProps || wrapUpProps.autoWrapup === false) {
423
+ _loggerProxy.default.info(`Auto wrap-up is not required for this task`, {
424
+ module: _constants2.TASK_FILE,
425
+ method: _constants.METHODS.SETUP_AUTO_WRAPUP_TIMER,
426
+ interactionId: this.data.interactionId
427
+ });
428
+ return;
429
+ }
430
+ const defaultWrapupReason = wrapUpProps.wrapUpReasonList?.find(r => r.isDefault) ?? wrapUpProps.wrapUpReasonList?.[0];
431
+ if (!defaultWrapupReason) {
432
+ _loggerProxy.default.error('No wrap-up reason configured', {
433
+ module: _constants2.TASK_FILE,
434
+ method: _constants.METHODS.SETUP_AUTO_WRAPUP_TIMER
435
+ });
436
+ return;
437
+ }
438
+ const intervalMs = wrapUpProps.autoWrapupInterval;
439
+ if (!intervalMs || intervalMs <= 0) {
440
+ _loggerProxy.default.error(`Invalid auto wrap-up interval: ${intervalMs}`, {
441
+ module: _constants2.TASK_FILE,
442
+ method: _constants.METHODS.SETUP_AUTO_WRAPUP_TIMER
443
+ });
444
+ return;
445
+ }
446
+ this.autoWrapup = new _AutoWrapup.default(intervalMs, wrapUpProps.allowCancelAutoWrapup);
447
+ this.autoWrapup.start(async () => {
448
+ _loggerProxy.default.info(`Auto wrap-up timer triggered`, {
449
+ module: _constants2.TASK_FILE,
450
+ method: _constants.METHODS.SETUP_AUTO_WRAPUP_TIMER,
451
+ interactionId: this.data.interactionId
452
+ });
453
+ await this.wrapup({
454
+ wrapUpReason: defaultWrapupReason.name,
455
+ auxCodeId: defaultWrapupReason.id
456
+ });
457
+ });
458
+ }
459
+ }
460
+
461
+ /**
462
+ * Cancels the automatic wrap-up timer if it's running
463
+ */
464
+ reconcileData(oldData, newData) {
465
+ Object.keys(newData).forEach(key => {
466
+ if (newData[key] && typeof newData[key] === 'object' && !Array.isArray(newData[key])) {
467
+ oldData[key] = this.reconcileData({
468
+ ...oldData[key]
469
+ }, newData[key]);
470
+ } else {
471
+ oldData[key] = newData[key];
472
+ }
473
+ });
474
+ return oldData;
475
+ }
476
+
477
+ /**
478
+ *
479
+ * @param methodName - The name of the method that is unsupported
480
+ * @throws Error
481
+ */
482
+ unsupportedMethodError(methodName) {
483
+ _loggerProxy.default.error(`Unsupported operation`, {
484
+ module: 'TASK',
485
+ method: methodName,
486
+ interactionId: this.data?.interactionId
487
+ });
488
+ throw new Error(`Unsupported operation: ${methodName}`);
489
+ }
490
+
491
+ /**
492
+ * This method is used to update the task data.
493
+ * @param updatedData - TaskData
494
+ * @param shouldOverwrite - boolean
495
+ * @example
496
+ * ```typescript
497
+ * task.updateTaskData(updatedData, true);
498
+ * ```
499
+ */
500
+ updateTaskData(updatedData, shouldOverwrite = false) {
501
+ this.data = shouldOverwrite ? updatedData : this.reconcileData(this.data, updatedData);
502
+ if (!shouldOverwrite) {
503
+ this.pruneStaleInteractionMaps(updatedData);
504
+ }
505
+ this.updateUiControls();
506
+ this.setupAutoWrapupTimer();
507
+ return this;
508
+ }
509
+
510
+ /**
511
+ * The backend sends `interaction.media` and `interaction.participants` as complete snapshots
512
+ * of the current call state. `reconcileData` deep-merges and never removes keys, so entries the
513
+ * backend dropped (e.g. a consult leg's media and consultee participant after the consult ends)
514
+ * linger in `this.data`. That stale data drives incorrect UI controls (e.g. the consult button
515
+ * staying disabled after the consult leg is gone, until a page refresh re-hydrates cleanly).
516
+ * Make only these two snapshot maps authoritative to the incoming payload, leaving every other
517
+ * field on the generic deep-merge path (CAD and other partial updates still merge as before).
518
+ */
519
+ pruneStaleInteractionMaps(incoming) {
520
+ const incomingInteraction = incoming?.interaction;
521
+ const currentInteraction = this.data?.interaction;
522
+ if (!incomingInteraction || !currentInteraction) {
523
+ return;
524
+ }
525
+ ['media', 'participants'].forEach(mapKey => {
526
+ const incomingMap = incomingInteraction[mapKey];
527
+ const currentMap = currentInteraction[mapKey];
528
+ if (!incomingMap || !currentMap || typeof incomingMap !== 'object') {
529
+ return;
530
+ }
531
+ Object.keys(currentMap).forEach(id => {
532
+ if (!(id in incomingMap)) {
533
+ delete currentMap[id];
534
+ }
535
+ });
536
+ });
537
+ }
538
+
539
+ /**
540
+ * This is used to blind transfer or vTeam transfer the task
541
+ * @param transferPayload
542
+ * @returns Promise<TaskResponse>
543
+ * @throws Error
544
+ * @example
545
+ * ```typescript
546
+ * const transferPayload = {
547
+ * to: 'myQueueId',
548
+ * destinationType: 'queue',
549
+ * }
550
+ * task.transfer(transferPayload).then(()=>{}).catch(()=>{});
551
+ * ```
552
+ */
553
+ async transfer(transferPayload) {
554
+ _loggerProxy.default.log(`Starting task transfer for taskId:${this.data.interactionId}`, {
555
+ module: 'Task',
556
+ method: 'transfer'
557
+ });
558
+ try {
559
+ this.metricsManager.timeEvent([_constants3.METRIC_EVENT_NAMES.TASK_TRANSFER_SUCCESS, _constants3.METRIC_EVENT_NAMES.TASK_TRANSFER_FAILED]);
560
+ let result;
561
+ if (transferPayload.destinationType === _types.DESTINATION_TYPE.QUEUE) {
562
+ result = await this.contact.vteamTransfer({
563
+ interactionId: this.data.interactionId,
564
+ data: transferPayload
565
+ });
566
+ } else {
567
+ result = await this.contact.blindTransfer({
568
+ interactionId: this.data.interactionId,
569
+ data: transferPayload
570
+ });
571
+ }
572
+ this.metricsManager.trackEvent(_constants3.METRIC_EVENT_NAMES.TASK_TRANSFER_SUCCESS, {
573
+ taskId: this.data.interactionId,
574
+ destination: transferPayload.to,
575
+ destinationType: transferPayload.destinationType,
576
+ isConsultTransfer: false,
577
+ ..._MetricsManager.default.getCommonTrackingFieldForAQMResponse(result)
578
+ }, ['operational', 'behavioral', 'business']);
579
+ return result;
580
+ } catch (error) {
581
+ const {
582
+ error: detailedError
583
+ } = (0, _Utils.getErrorDetails)(error, 'transfer', _constants2.CC_FILE);
584
+ this.metricsManager.trackEvent(_constants3.METRIC_EVENT_NAMES.TASK_TRANSFER_FAILED, {
585
+ taskId: this.data.interactionId,
586
+ destination: transferPayload.to,
587
+ destinationType: transferPayload.destinationType,
588
+ isConsultTransfer: false,
589
+ error: error.toString(),
590
+ ..._MetricsManager.default.getCommonTrackingFieldForAQMResponseFailed(error.details || {})
591
+ }, ['operational', 'behavioral', 'business']);
592
+ throw detailedError;
593
+ }
594
+ }
595
+
596
+ /**
597
+ * This is used to end the task.
598
+ * @returns Promise<TaskResponse>
599
+ * @throws Error
600
+ * @example
601
+ * ```typescript
602
+ * task.end().then(()=>{}).catch(()=>{})
603
+ * ```
604
+ */
605
+ async end() {
606
+ _loggerProxy.default.log(`Ending task for taskId:${this.data.interactionId}`, {
607
+ module: 'Task',
608
+ method: 'end'
609
+ });
610
+ const requestInteractionId = this.data.interaction?.mainInteractionId || this.data.interactionId;
611
+ try {
612
+ this.metricsManager.timeEvent([_constants3.METRIC_EVENT_NAMES.TASK_END_SUCCESS, _constants3.METRIC_EVENT_NAMES.TASK_END_FAILED]);
613
+ const response = await this.contact.end({
614
+ interactionId: requestInteractionId
615
+ });
616
+ this.metricsManager.trackEvent(_constants3.METRIC_EVENT_NAMES.TASK_END_SUCCESS, {
617
+ taskId: this.data.interactionId,
618
+ requestInteractionId,
619
+ ..._MetricsManager.default.getCommonTrackingFieldForAQMResponse(response)
620
+ }, ['operational', 'behavioral', 'business']);
621
+ return response;
622
+ } catch (error) {
623
+ const {
624
+ error: detailedError
625
+ } = (0, _Utils.getErrorDetails)(error, 'end', _constants2.CC_FILE);
626
+ this.metricsManager.trackEvent(_constants3.METRIC_EVENT_NAMES.TASK_END_FAILED, {
627
+ taskId: this.data.interactionId,
628
+ requestInteractionId,
629
+ ..._MetricsManager.default.getCommonTrackingFieldForAQMResponseFailed(error.details || {})
630
+ }, ['operational', 'behavioral', 'business']);
631
+ throw detailedError;
632
+ }
633
+ }
634
+
635
+ /**
636
+ * This is used to wrap up the task.
637
+ * @param wrapupPayload - WrapupPayLoad
638
+ * @returns Promise<TaskResponse>
639
+ * @throws Error
640
+ * @example
641
+ * ```typescript
642
+ * task.wrapup(wrapupPayload).then(()=>{}).catch(()=>{})
643
+ * ```
644
+ */
645
+ async wrapup(wrapupPayload) {
646
+ this.cancelAutoWrapupTimer();
647
+ _loggerProxy.default.log(`Starting task wrapup for taskId:${this.data.interactionId}`, {
648
+ module: 'Task',
649
+ method: 'wrapup'
650
+ });
651
+ try {
652
+ this.metricsManager.timeEvent([_constants3.METRIC_EVENT_NAMES.TASK_WRAPUP_SUCCESS, _constants3.METRIC_EVENT_NAMES.TASK_WRAPUP_FAILED]);
653
+ if (!this.data) {
654
+ throw new Error('No task data available');
655
+ }
656
+ if (!wrapupPayload.auxCodeId || wrapupPayload.auxCodeId.length === 0) {
657
+ throw new Error('AuxCodeId is required');
658
+ }
659
+ if (!wrapupPayload.wrapUpReason || wrapupPayload.wrapUpReason.length === 0) {
660
+ throw new Error('WrapUpReason is required');
661
+ }
662
+ const response = await this.contact.wrapup({
663
+ interactionId: this.data.interactionId,
664
+ data: wrapupPayload
665
+ });
666
+ this.metricsManager.trackEvent(_constants3.METRIC_EVENT_NAMES.TASK_WRAPUP_SUCCESS, {
667
+ taskId: this.data.interactionId,
668
+ wrapUpCode: wrapupPayload.auxCodeId,
669
+ wrapUpReason: wrapupPayload.wrapUpReason,
670
+ ..._MetricsManager.default.getCommonTrackingFieldForAQMResponse(response)
671
+ }, ['operational', 'behavioral', 'business']);
672
+ return response;
673
+ } catch (error) {
674
+ const {
675
+ error: detailedError
676
+ } = (0, _Utils.getErrorDetails)(error, 'wrapup', _constants2.CC_FILE);
677
+ this.metricsManager.trackEvent(_constants3.METRIC_EVENT_NAMES.TASK_WRAPUP_FAILED, {
678
+ taskId: this.data.interactionId,
679
+ wrapUpCode: wrapupPayload.auxCodeId,
680
+ wrapUpReason: wrapupPayload.wrapUpReason,
681
+ ..._MetricsManager.default.getCommonTrackingFieldForAQMResponseFailed(error.details || {})
682
+ }, ['operational', 'behavioral', 'business']);
683
+ throw detailedError;
684
+ }
685
+ }
686
+ }
687
+ exports.default = Task;
688
+ //# sourceMappingURL=Task.js.map