@webex/contact-center 3.12.0-next.9 → 3.12.0-task-refactor.2

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 (200) 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 +65 -123
  24. package/dist/cc.js.map +1 -1
  25. package/dist/constants.js +13 -2
  26. package/dist/constants.js.map +1 -1
  27. package/dist/index.js +13 -5
  28. package/dist/index.js.map +1 -1
  29. package/dist/metrics/behavioral-events.js +26 -13
  30. package/dist/metrics/behavioral-events.js.map +1 -1
  31. package/dist/metrics/constants.js +7 -6
  32. package/dist/metrics/constants.js.map +1 -1
  33. package/dist/services/ApiAiAssistant.js +0 -3
  34. package/dist/services/ApiAiAssistant.js.map +1 -1
  35. package/dist/services/config/Util.js +2 -3
  36. package/dist/services/config/Util.js.map +1 -1
  37. package/dist/services/config/types.js +16 -14
  38. package/dist/services/config/types.js.map +1 -1
  39. package/dist/services/constants.js +0 -1
  40. package/dist/services/constants.js.map +1 -1
  41. package/dist/services/core/Err.js.map +1 -1
  42. package/dist/services/core/Utils.js +79 -55
  43. package/dist/services/core/Utils.js.map +1 -1
  44. package/dist/services/core/aqm-reqs.js +17 -92
  45. package/dist/services/core/aqm-reqs.js.map +1 -1
  46. package/dist/services/core/websocket/WebSocketManager.js +5 -25
  47. package/dist/services/core/websocket/WebSocketManager.js.map +1 -1
  48. package/dist/services/core/websocket/types.js.map +1 -1
  49. package/dist/services/index.js +1 -2
  50. package/dist/services/index.js.map +1 -1
  51. package/dist/services/task/Task.js +644 -0
  52. package/dist/services/task/Task.js.map +1 -0
  53. package/dist/services/task/TaskFactory.js +45 -0
  54. package/dist/services/task/TaskFactory.js.map +1 -0
  55. package/dist/services/task/TaskManager.js +570 -535
  56. package/dist/services/task/TaskManager.js.map +1 -1
  57. package/dist/services/task/TaskUtils.js +132 -28
  58. package/dist/services/task/TaskUtils.js.map +1 -1
  59. package/dist/services/task/constants.js +7 -6
  60. package/dist/services/task/constants.js.map +1 -1
  61. package/dist/services/task/dialer.js +0 -51
  62. package/dist/services/task/dialer.js.map +1 -1
  63. package/dist/services/task/digital/Digital.js +77 -0
  64. package/dist/services/task/digital/Digital.js.map +1 -0
  65. package/dist/services/task/state-machine/TaskStateMachine.js +634 -0
  66. package/dist/services/task/state-machine/TaskStateMachine.js.map +1 -0
  67. package/dist/services/task/state-machine/actions.js +372 -0
  68. package/dist/services/task/state-machine/actions.js.map +1 -0
  69. package/dist/services/task/state-machine/constants.js +139 -0
  70. package/dist/services/task/state-machine/constants.js.map +1 -0
  71. package/dist/services/task/state-machine/guards.js +263 -0
  72. package/dist/services/task/state-machine/guards.js.map +1 -0
  73. package/dist/services/task/state-machine/index.js +53 -0
  74. package/dist/services/task/state-machine/index.js.map +1 -0
  75. package/dist/services/task/state-machine/types.js +54 -0
  76. package/dist/services/task/state-machine/types.js.map +1 -0
  77. package/dist/services/task/state-machine/uiControlsComputer.js +377 -0
  78. package/dist/services/task/state-machine/uiControlsComputer.js.map +1 -0
  79. package/dist/services/task/taskDataNormalizer.js +99 -0
  80. package/dist/services/task/taskDataNormalizer.js.map +1 -0
  81. package/dist/services/task/types.js +157 -18
  82. package/dist/services/task/types.js.map +1 -1
  83. package/dist/services/task/voice/Voice.js +1031 -0
  84. package/dist/services/task/voice/Voice.js.map +1 -0
  85. package/dist/services/task/voice/WebRTC.js +149 -0
  86. package/dist/services/task/voice/WebRTC.js.map +1 -0
  87. package/dist/types/cc.d.ts +4 -33
  88. package/dist/types/constants.d.ts +13 -2
  89. package/dist/types/index.d.ts +11 -5
  90. package/dist/types/metrics/constants.d.ts +5 -3
  91. package/dist/types/services/ApiAiAssistant.d.ts +1 -1
  92. package/dist/types/services/config/types.d.ts +97 -25
  93. package/dist/types/services/core/Err.d.ts +0 -2
  94. package/dist/types/services/core/Utils.d.ts +25 -23
  95. package/dist/types/services/core/aqm-reqs.d.ts +0 -49
  96. package/dist/types/services/core/websocket/WebSocketManager.d.ts +1 -1
  97. package/dist/types/services/core/websocket/connection-service.d.ts +0 -1
  98. package/dist/types/services/core/websocket/types.d.ts +1 -1
  99. package/dist/types/services/index.d.ts +1 -1
  100. package/dist/types/services/task/Task.d.ts +146 -0
  101. package/dist/types/services/task/TaskFactory.d.ts +12 -0
  102. package/dist/types/services/task/TaskUtils.d.ts +39 -8
  103. package/dist/types/services/task/constants.d.ts +5 -4
  104. package/dist/types/services/task/dialer.d.ts +0 -15
  105. package/dist/types/services/task/digital/Digital.d.ts +22 -0
  106. package/dist/types/services/task/state-machine/TaskStateMachine.d.ts +906 -0
  107. package/dist/types/services/task/state-machine/actions.d.ts +8 -0
  108. package/dist/types/services/task/state-machine/constants.d.ts +91 -0
  109. package/dist/types/services/task/state-machine/guards.d.ts +78 -0
  110. package/dist/types/services/task/state-machine/index.d.ts +13 -0
  111. package/dist/types/services/task/state-machine/types.d.ts +256 -0
  112. package/dist/types/services/task/state-machine/uiControlsComputer.d.ts +9 -0
  113. package/dist/types/services/task/taskDataNormalizer.d.ts +10 -0
  114. package/dist/types/services/task/types.d.ts +539 -88
  115. package/dist/types/services/task/voice/Voice.d.ts +183 -0
  116. package/dist/types/services/task/voice/WebRTC.d.ts +53 -0
  117. package/dist/types/types.d.ts +68 -0
  118. package/dist/types/webex.d.ts +1 -0
  119. package/dist/types.js +70 -0
  120. package/dist/types.js.map +1 -1
  121. package/dist/webex.js +14 -2
  122. package/dist/webex.js.map +1 -1
  123. package/package.json +14 -11
  124. package/src/cc.ts +91 -177
  125. package/src/constants.ts +13 -2
  126. package/src/index.ts +14 -5
  127. package/src/metrics/ai-docs/AGENTS.md +348 -0
  128. package/src/metrics/ai-docs/ARCHITECTURE.md +336 -0
  129. package/src/metrics/behavioral-events.ts +28 -14
  130. package/src/metrics/constants.ts +7 -8
  131. package/src/services/ApiAiAssistant.ts +2 -4
  132. package/src/services/agent/ai-docs/AGENTS.md +238 -0
  133. package/src/services/agent/ai-docs/ARCHITECTURE.md +302 -0
  134. package/src/services/ai-docs/AGENTS.md +384 -0
  135. package/src/services/config/Util.ts +2 -3
  136. package/src/services/config/ai-docs/AGENTS.md +253 -0
  137. package/src/services/config/ai-docs/ARCHITECTURE.md +424 -0
  138. package/src/services/config/types.ts +108 -20
  139. package/src/services/constants.ts +0 -1
  140. package/src/services/core/Err.ts +0 -1
  141. package/src/services/core/Utils.ts +90 -67
  142. package/src/services/core/ai-docs/AGENTS.md +379 -0
  143. package/src/services/core/ai-docs/ARCHITECTURE.md +696 -0
  144. package/src/services/core/aqm-reqs.ts +22 -100
  145. package/src/services/core/websocket/WebSocketManager.ts +4 -23
  146. package/src/services/core/websocket/types.ts +1 -1
  147. package/src/services/index.ts +1 -2
  148. package/src/services/task/Task.ts +785 -0
  149. package/src/services/task/TaskFactory.ts +55 -0
  150. package/src/services/task/TaskManager.ts +579 -633
  151. package/src/services/task/TaskUtils.ts +175 -31
  152. package/src/services/task/ai-docs/AGENTS.md +448 -0
  153. package/src/services/task/ai-docs/ARCHITECTURE.md +573 -0
  154. package/src/services/task/constants.ts +5 -4
  155. package/src/services/task/dialer.ts +1 -56
  156. package/src/services/task/digital/Digital.ts +95 -0
  157. package/src/services/task/state-machine/TaskStateMachine.ts +793 -0
  158. package/src/services/task/state-machine/actions.ts +422 -0
  159. package/src/services/task/state-machine/ai-docs/AGENTS.md +495 -0
  160. package/src/services/task/state-machine/ai-docs/ARCHITECTURE.md +1135 -0
  161. package/src/services/task/state-machine/constants.ts +150 -0
  162. package/src/services/task/state-machine/guards.ts +303 -0
  163. package/src/services/task/state-machine/index.ts +28 -0
  164. package/src/services/task/state-machine/types.ts +228 -0
  165. package/src/services/task/state-machine/uiControlsComputer.ts +542 -0
  166. package/src/services/task/taskDataNormalizer.ts +137 -0
  167. package/src/services/task/types.ts +641 -95
  168. package/src/services/task/voice/Voice.ts +1255 -0
  169. package/src/services/task/voice/WebRTC.ts +187 -0
  170. package/src/types.ts +88 -5
  171. package/src/utils/AGENTS.md +276 -0
  172. package/src/webex.js +2 -0
  173. package/test/unit/spec/cc.ts +59 -142
  174. package/test/unit/spec/logger-proxy.ts +70 -0
  175. package/test/unit/spec/services/ApiAiAssistant.ts +17 -0
  176. package/test/unit/spec/services/config/index.ts +26 -55
  177. package/test/unit/spec/services/core/Utils.ts +103 -52
  178. package/test/unit/spec/services/core/websocket/WebSocketManager.ts +48 -112
  179. package/test/unit/spec/services/core/websocket/connection-service.ts +5 -4
  180. package/test/unit/spec/services/task/AutoWrapup.ts +63 -0
  181. package/test/unit/spec/services/task/Task.ts +416 -0
  182. package/test/unit/spec/services/task/TaskFactory.ts +62 -0
  183. package/test/unit/spec/services/task/TaskManager.ts +781 -1735
  184. package/test/unit/spec/services/task/TaskUtils.ts +125 -0
  185. package/test/unit/spec/services/task/dialer.ts +112 -198
  186. package/test/unit/spec/services/task/digital/Digital.ts +105 -0
  187. package/test/unit/spec/services/task/state-machine/TaskStateMachine.ts +473 -0
  188. package/test/unit/spec/services/task/state-machine/guards.ts +288 -0
  189. package/test/unit/spec/services/task/state-machine/types.ts +18 -0
  190. package/test/unit/spec/services/task/state-machine/uiControlsComputer.ts +147 -0
  191. package/test/unit/spec/services/task/taskTestUtils.ts +87 -0
  192. package/test/unit/spec/services/task/voice/Voice.ts +587 -0
  193. package/test/unit/spec/services/task/voice/WebRTC.ts +242 -0
  194. package/umd/contact-center.min.js +2 -2
  195. package/umd/contact-center.min.js.map +1 -1
  196. package/dist/services/task/index.js +0 -1525
  197. package/dist/services/task/index.js.map +0 -1
  198. package/dist/types/services/task/index.d.ts +0 -650
  199. package/src/services/task/index.ts +0 -1801
  200. package/test/unit/spec/services/task/index.ts +0 -2184
@@ -0,0 +1,644 @@
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
+ return (0, _uiControlsComputer.computeUIControls)(currentState, context, this.data);
204
+ }
205
+
206
+ /**
207
+ * Stop the state machine service
208
+ */
209
+ stopStateMachine() {
210
+ if (this.stateMachineService) {
211
+ this.stateMachineService.stop();
212
+ this.stateMachineService = undefined;
213
+ }
214
+ }
215
+ static extractTaskDataFromEvent(event) {
216
+ if (!event || typeof event !== 'object') {
217
+ return undefined;
218
+ }
219
+ if ('taskData' in event) {
220
+ return event.taskData;
221
+ }
222
+ return undefined;
223
+ }
224
+ async autoAnswerIfNeeded() {
225
+ if (!this.data) {
226
+ return;
227
+ }
228
+ const autoAnswerSupported = this.uiControlConfig.channelType === _types.TASK_CHANNEL_TYPE.DIGITAL || this.uiControlConfig.voiceVariant === _types.VOICE_VARIANT.WEBRTC;
229
+ if (!autoAnswerSupported) {
230
+ return;
231
+ }
232
+ const shouldAutoAnswer = this.data.isAutoAnswering === true;
233
+ if (!shouldAutoAnswer) {
234
+ return;
235
+ }
236
+ _loggerProxy.default.info(`Auto-answering task`, {
237
+ module: _constants2.TASK_FILE,
238
+ method: 'autoAnswerIfNeeded',
239
+ interactionId: this.data.interactionId
240
+ });
241
+ try {
242
+ await this.accept();
243
+ _loggerProxy.default.info(`Task auto-answered successfully`, {
244
+ module: _constants2.TASK_FILE,
245
+ method: 'autoAnswerIfNeeded',
246
+ interactionId: this.data.interactionId
247
+ });
248
+ this.metricsManager.trackEvent(_constants3.METRIC_EVENT_NAMES.TASK_AUTO_ANSWER_SUCCESS, {
249
+ taskId: this.data.interactionId,
250
+ mediaType: this.data.interaction.mediaType,
251
+ isAutoAnswered: true
252
+ }, ['behavioral', 'operational']);
253
+ this.emit(_types.TASK_EVENTS.TASK_AUTO_ANSWERED, this);
254
+ } catch (error) {
255
+ this.updateTaskData({
256
+ ...this.data,
257
+ isAutoAnswering: false
258
+ });
259
+ _loggerProxy.default.error(`Failed to auto-answer task`, {
260
+ module: _constants2.TASK_FILE,
261
+ method: 'autoAnswerIfNeeded',
262
+ interactionId: this.data.interactionId,
263
+ error
264
+ });
265
+ this.metricsManager.trackEvent(_constants3.METRIC_EVENT_NAMES.TASK_AUTO_ANSWER_FAILED, {
266
+ taskId: this.data.interactionId,
267
+ mediaType: this.data.interaction.mediaType,
268
+ error: error?.message || 'Unknown error',
269
+ isAutoAnswered: false
270
+ }, ['behavioral', 'operational']);
271
+ }
272
+ }
273
+ updateTaskFromEvent(event) {
274
+ const taskData = Task.extractTaskDataFromEvent(event);
275
+ if (taskData) {
276
+ this.updateTaskData(taskData);
277
+ }
278
+ }
279
+ getStateMachineActionOverrides() {
280
+ return {
281
+ ...this.getCommonActionOverrides(),
282
+ ...this.getChannelSpecificActionOverrides()
283
+ };
284
+ }
285
+ getChannelSpecificActionOverrides() {
286
+ return {};
287
+ }
288
+ createEmitSelfAction(taskEvent, {
289
+ updateTaskData = false
290
+ } = {}) {
291
+ return ({
292
+ event
293
+ }) => {
294
+ if (updateTaskData) {
295
+ this.updateTaskFromEvent(event);
296
+ }
297
+ _loggerProxy.default.info(`Emitting task event ${taskEvent}`, {
298
+ module: _constants2.TASK_FILE,
299
+ method: 'emitTaskEvent',
300
+ interactionId: this.data?.interactionId
301
+ });
302
+ this.emit(taskEvent, this);
303
+ };
304
+ }
305
+ getCommonActionOverrides() {
306
+ return {
307
+ syncTaskDataFromEvent: ({
308
+ event
309
+ }) => {
310
+ this.updateTaskFromEvent(event);
311
+ },
312
+ emitTaskIncoming: this.createEmitSelfAction(_types.TASK_EVENTS.TASK_INCOMING, {
313
+ updateTaskData: true
314
+ }),
315
+ emitTaskHydrate: this.createEmitSelfAction(_types.TASK_EVENTS.TASK_HYDRATE, {
316
+ updateTaskData: true
317
+ }),
318
+ emitTaskOfferContact: this.createEmitSelfAction(_types.TASK_EVENTS.TASK_OFFER_CONTACT, {
319
+ updateTaskData: true
320
+ }),
321
+ emitTaskAssigned: this.createEmitSelfAction(_types.TASK_EVENTS.TASK_ASSIGNED, {
322
+ updateTaskData: true
323
+ }),
324
+ emitTaskEnd: this.createEmitSelfAction(_types.TASK_EVENTS.TASK_END, {
325
+ updateTaskData: true
326
+ }),
327
+ emitTaskOfferConsult: this.createEmitSelfAction(_types.TASK_EVENTS.TASK_OFFER_CONSULT, {
328
+ updateTaskData: true
329
+ }),
330
+ emitTaskConsultCreated: this.createEmitSelfAction(_types.TASK_EVENTS.TASK_CONSULT_CREATED, {
331
+ updateTaskData: true
332
+ }),
333
+ emitTaskConsulting: ({
334
+ event
335
+ }) => {
336
+ this.updateTaskFromEvent(event);
337
+ if (this.data.isConsulted) {
338
+ this.emit(_types.TASK_EVENTS.TASK_CONSULT_ACCEPTED, this);
339
+ } else {
340
+ this.emit(_types.TASK_EVENTS.TASK_CONSULTING, this);
341
+ }
342
+ },
343
+ emitTaskConsultAccepted: this.createEmitSelfAction(_types.TASK_EVENTS.TASK_CONSULT_ACCEPTED),
344
+ emitTaskConsultEnd: this.createEmitSelfAction(_types.TASK_EVENTS.TASK_CONSULT_END, {
345
+ updateTaskData: true
346
+ }),
347
+ emitTaskConsultQueueCancelled: this.createEmitSelfAction(_types.TASK_EVENTS.TASK_CONSULT_QUEUE_CANCELLED, {
348
+ updateTaskData: true
349
+ }),
350
+ emitTaskConsultQueueFailed: this.createEmitSelfAction(_types.TASK_EVENTS.TASK_CONSULT_QUEUE_FAILED, {
351
+ updateTaskData: true
352
+ }),
353
+ emitTaskReject: ({
354
+ event
355
+ }) => {
356
+ this.updateTaskFromEvent(event);
357
+ const reason = event && typeof event === 'object' && 'reason' in event ? event.reason : undefined;
358
+ this.emit(_types.TASK_EVENTS.TASK_REJECT, reason);
359
+ },
360
+ emitTaskWrapup: ({
361
+ event
362
+ }) => {
363
+ this.updateTaskFromEvent(event);
364
+ const shouldEmitWrapup = Boolean(this.data.wrapUpRequired);
365
+ if (!shouldEmitWrapup) {
366
+ _loggerProxy.default.info(`Skipping task:wrapup event - wrapUpRequired is false`, {
367
+ module: _constants2.TASK_FILE,
368
+ method: 'emitTaskEvent',
369
+ interactionId: this.data?.interactionId
370
+ });
371
+ return;
372
+ }
373
+ _loggerProxy.default.info(`Emitting task event ${_types.TASK_EVENTS.TASK_WRAPUP}`, {
374
+ module: _constants2.TASK_FILE,
375
+ method: 'emitTaskEvent',
376
+ interactionId: this.data?.interactionId
377
+ });
378
+ this.emit(_types.TASK_EVENTS.TASK_WRAPUP, this);
379
+ },
380
+ emitTaskWrappedup: this.createEmitSelfAction(_types.TASK_EVENTS.TASK_WRAPPEDUP, {
381
+ updateTaskData: true
382
+ }),
383
+ requestAutoAnswer: ({
384
+ event
385
+ }) => {
386
+ if (event) {
387
+ // parameter intentionally unused
388
+ }
389
+ this.autoAnswerIfNeeded();
390
+ },
391
+ requestCleanup: () => {
392
+ this.emit(_types.TASK_EVENTS.TASK_CLEANUP, this, {
393
+ removeFromCollection: false
394
+ });
395
+ },
396
+ cleanupResources: () => {
397
+ this.emit(_types.TASK_EVENTS.TASK_CLEANUP, this, {
398
+ removeFromCollection: true
399
+ });
400
+ }
401
+ };
402
+ }
403
+
404
+ /**
405
+ * Sets up the automatic wrap-up timer if wrap-up is required
406
+ */
407
+ setupAutoWrapupTimer() {
408
+ if (this.data.wrapUpRequired && !this.autoWrapup && this.wrapupData && this.wrapupData.wrapUpProps) {
409
+ const wrapUpProps = this.wrapupData.wrapUpProps;
410
+ if (!wrapUpProps || wrapUpProps.autoWrapup === false) {
411
+ _loggerProxy.default.info(`Auto wrap-up is not required for this task`, {
412
+ module: _constants2.TASK_FILE,
413
+ method: _constants.METHODS.SETUP_AUTO_WRAPUP_TIMER,
414
+ interactionId: this.data.interactionId
415
+ });
416
+ return;
417
+ }
418
+ const defaultWrapupReason = wrapUpProps.wrapUpReasonList?.find(r => r.isDefault) ?? wrapUpProps.wrapUpReasonList?.[0];
419
+ if (!defaultWrapupReason) {
420
+ _loggerProxy.default.error('No wrap-up reason configured', {
421
+ module: _constants2.TASK_FILE,
422
+ method: _constants.METHODS.SETUP_AUTO_WRAPUP_TIMER
423
+ });
424
+ return;
425
+ }
426
+ const intervalMs = wrapUpProps.autoWrapupInterval;
427
+ if (!intervalMs || intervalMs <= 0) {
428
+ _loggerProxy.default.error(`Invalid auto wrap-up interval: ${intervalMs}`, {
429
+ module: _constants2.TASK_FILE,
430
+ method: _constants.METHODS.SETUP_AUTO_WRAPUP_TIMER
431
+ });
432
+ return;
433
+ }
434
+ this.autoWrapup = new _AutoWrapup.default(intervalMs, wrapUpProps.allowCancelAutoWrapup);
435
+ this.autoWrapup.start(async () => {
436
+ _loggerProxy.default.info(`Auto wrap-up timer triggered`, {
437
+ module: _constants2.TASK_FILE,
438
+ method: _constants.METHODS.SETUP_AUTO_WRAPUP_TIMER,
439
+ interactionId: this.data.interactionId
440
+ });
441
+ await this.wrapup({
442
+ wrapUpReason: defaultWrapupReason.name,
443
+ auxCodeId: defaultWrapupReason.id
444
+ });
445
+ });
446
+ }
447
+ }
448
+
449
+ /**
450
+ * Cancels the automatic wrap-up timer if it's running
451
+ */
452
+ reconcileData(oldData, newData) {
453
+ Object.keys(newData).forEach(key => {
454
+ if (newData[key] && typeof newData[key] === 'object' && !Array.isArray(newData[key])) {
455
+ oldData[key] = this.reconcileData({
456
+ ...oldData[key]
457
+ }, newData[key]);
458
+ } else {
459
+ oldData[key] = newData[key];
460
+ }
461
+ });
462
+ return oldData;
463
+ }
464
+
465
+ /**
466
+ *
467
+ * @param methodName - The name of the method that is unsupported
468
+ * @throws Error
469
+ */
470
+ unsupportedMethodError(methodName) {
471
+ _loggerProxy.default.error(`Unsupported operation`, {
472
+ module: 'TASK',
473
+ method: methodName,
474
+ interactionId: this.data?.interactionId
475
+ });
476
+ throw new Error(`Unsupported operation: ${methodName}`);
477
+ }
478
+
479
+ /**
480
+ * This method is used to update the task data.
481
+ * @param updatedData - TaskData
482
+ * @param shouldOverwrite - boolean
483
+ * @example
484
+ * ```typescript
485
+ * task.updateTaskData(updatedData, true);
486
+ * ```
487
+ */
488
+ updateTaskData(updatedData, shouldOverwrite = false) {
489
+ this.data = shouldOverwrite ? updatedData : this.reconcileData(this.data, updatedData);
490
+ this.updateUiControls();
491
+ this.setupAutoWrapupTimer();
492
+ return this;
493
+ }
494
+
495
+ /**
496
+ * This is used to blind transfer or vTeam transfer the task
497
+ * @param transferPayload
498
+ * @returns Promise<TaskResponse>
499
+ * @throws Error
500
+ * @example
501
+ * ```typescript
502
+ * const transferPayload = {
503
+ * to: 'myQueueId',
504
+ * destinationType: 'queue',
505
+ * }
506
+ * task.transfer(transferPayload).then(()=>{}).catch(()=>{});
507
+ * ```
508
+ */
509
+ async transfer(transferPayload) {
510
+ _loggerProxy.default.log(`Starting task transfer for taskId:${this.data.interactionId}`, {
511
+ module: 'Task',
512
+ method: 'transfer'
513
+ });
514
+ try {
515
+ this.metricsManager.timeEvent([_constants3.METRIC_EVENT_NAMES.TASK_TRANSFER_SUCCESS, _constants3.METRIC_EVENT_NAMES.TASK_TRANSFER_FAILED]);
516
+ let result;
517
+ if (transferPayload.destinationType === _types.DESTINATION_TYPE.QUEUE) {
518
+ result = await this.contact.vteamTransfer({
519
+ interactionId: this.data.interactionId,
520
+ data: transferPayload
521
+ });
522
+ } else {
523
+ result = await this.contact.blindTransfer({
524
+ interactionId: this.data.interactionId,
525
+ data: transferPayload
526
+ });
527
+ }
528
+ this.metricsManager.trackEvent(_constants3.METRIC_EVENT_NAMES.TASK_TRANSFER_SUCCESS, {
529
+ taskId: this.data.interactionId,
530
+ destination: transferPayload.to,
531
+ destinationType: transferPayload.destinationType,
532
+ isConsultTransfer: false,
533
+ ..._MetricsManager.default.getCommonTrackingFieldForAQMResponse(result)
534
+ }, ['operational', 'behavioral', 'business']);
535
+ return result;
536
+ } catch (error) {
537
+ const {
538
+ error: detailedError
539
+ } = (0, _Utils.getErrorDetails)(error, 'transfer', _constants2.CC_FILE);
540
+ this.metricsManager.trackEvent(_constants3.METRIC_EVENT_NAMES.TASK_TRANSFER_FAILED, {
541
+ taskId: this.data.interactionId,
542
+ destination: transferPayload.to,
543
+ destinationType: transferPayload.destinationType,
544
+ isConsultTransfer: false,
545
+ error: error.toString(),
546
+ ..._MetricsManager.default.getCommonTrackingFieldForAQMResponseFailed(error.details || {})
547
+ }, ['operational', 'behavioral', 'business']);
548
+ throw detailedError;
549
+ }
550
+ }
551
+
552
+ /**
553
+ * This is used to end the task.
554
+ * @returns Promise<TaskResponse>
555
+ * @throws Error
556
+ * @example
557
+ * ```typescript
558
+ * task.end().then(()=>{}).catch(()=>{})
559
+ * ```
560
+ */
561
+ async end() {
562
+ _loggerProxy.default.log(`Ending task for taskId:${this.data.interactionId}`, {
563
+ module: 'Task',
564
+ method: 'end'
565
+ });
566
+ const requestInteractionId = this.data.interaction?.mainInteractionId || this.data.interactionId;
567
+ try {
568
+ this.metricsManager.timeEvent([_constants3.METRIC_EVENT_NAMES.TASK_END_SUCCESS, _constants3.METRIC_EVENT_NAMES.TASK_END_FAILED]);
569
+ const response = await this.contact.end({
570
+ interactionId: requestInteractionId
571
+ });
572
+ this.metricsManager.trackEvent(_constants3.METRIC_EVENT_NAMES.TASK_END_SUCCESS, {
573
+ taskId: this.data.interactionId,
574
+ requestInteractionId,
575
+ ..._MetricsManager.default.getCommonTrackingFieldForAQMResponse(response)
576
+ }, ['operational', 'behavioral', 'business']);
577
+ return response;
578
+ } catch (error) {
579
+ const {
580
+ error: detailedError
581
+ } = (0, _Utils.getErrorDetails)(error, 'end', _constants2.CC_FILE);
582
+ this.metricsManager.trackEvent(_constants3.METRIC_EVENT_NAMES.TASK_END_FAILED, {
583
+ taskId: this.data.interactionId,
584
+ requestInteractionId,
585
+ ..._MetricsManager.default.getCommonTrackingFieldForAQMResponseFailed(error.details || {})
586
+ }, ['operational', 'behavioral', 'business']);
587
+ throw detailedError;
588
+ }
589
+ }
590
+
591
+ /**
592
+ * This is used to wrap up the task.
593
+ * @param wrapupPayload - WrapupPayLoad
594
+ * @returns Promise<TaskResponse>
595
+ * @throws Error
596
+ * @example
597
+ * ```typescript
598
+ * task.wrapup(wrapupPayload).then(()=>{}).catch(()=>{})
599
+ * ```
600
+ */
601
+ async wrapup(wrapupPayload) {
602
+ this.cancelAutoWrapupTimer();
603
+ _loggerProxy.default.log(`Starting task wrapup for taskId:${this.data.interactionId}`, {
604
+ module: 'Task',
605
+ method: 'wrapup'
606
+ });
607
+ try {
608
+ this.metricsManager.timeEvent([_constants3.METRIC_EVENT_NAMES.TASK_WRAPUP_SUCCESS, _constants3.METRIC_EVENT_NAMES.TASK_WRAPUP_FAILED]);
609
+ if (!this.data) {
610
+ throw new Error('No task data available');
611
+ }
612
+ if (!wrapupPayload.auxCodeId || wrapupPayload.auxCodeId.length === 0) {
613
+ throw new Error('AuxCodeId is required');
614
+ }
615
+ if (!wrapupPayload.wrapUpReason || wrapupPayload.wrapUpReason.length === 0) {
616
+ throw new Error('WrapUpReason is required');
617
+ }
618
+ const response = await this.contact.wrapup({
619
+ interactionId: this.data.interactionId,
620
+ data: wrapupPayload
621
+ });
622
+ this.metricsManager.trackEvent(_constants3.METRIC_EVENT_NAMES.TASK_WRAPUP_SUCCESS, {
623
+ taskId: this.data.interactionId,
624
+ wrapUpCode: wrapupPayload.auxCodeId,
625
+ wrapUpReason: wrapupPayload.wrapUpReason,
626
+ ..._MetricsManager.default.getCommonTrackingFieldForAQMResponse(response)
627
+ }, ['operational', 'behavioral', 'business']);
628
+ return response;
629
+ } catch (error) {
630
+ const {
631
+ error: detailedError
632
+ } = (0, _Utils.getErrorDetails)(error, 'wrapup', _constants2.CC_FILE);
633
+ this.metricsManager.trackEvent(_constants3.METRIC_EVENT_NAMES.TASK_WRAPUP_FAILED, {
634
+ taskId: this.data.interactionId,
635
+ wrapUpCode: wrapupPayload.auxCodeId,
636
+ wrapUpReason: wrapupPayload.wrapUpReason,
637
+ ..._MetricsManager.default.getCommonTrackingFieldForAQMResponseFailed(error.details || {})
638
+ }, ['operational', 'behavioral', 'business']);
639
+ throw detailedError;
640
+ }
641
+ }
642
+ }
643
+ exports.default = Task;
644
+ //# sourceMappingURL=Task.js.map