@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.
- package/AGENTS.md +438 -0
- package/ai-docs/README.md +131 -0
- package/ai-docs/RULES.md +455 -0
- package/ai-docs/patterns/event-driven-patterns.md +485 -0
- package/ai-docs/patterns/testing-patterns.md +480 -0
- package/ai-docs/patterns/typescript-patterns.md +365 -0
- package/ai-docs/templates/README.md +102 -0
- package/ai-docs/templates/documentation/create-agents-md.md +240 -0
- package/ai-docs/templates/documentation/create-architecture-md.md +295 -0
- package/ai-docs/templates/existing-service/bug-fix.md +254 -0
- package/ai-docs/templates/existing-service/feature-enhancement.md +450 -0
- package/ai-docs/templates/new-method/00-master.md +80 -0
- package/ai-docs/templates/new-method/01-requirements.md +232 -0
- package/ai-docs/templates/new-method/02-implementation.md +295 -0
- package/ai-docs/templates/new-method/03-tests.md +201 -0
- package/ai-docs/templates/new-method/04-validation.md +141 -0
- package/ai-docs/templates/new-service/00-master.md +109 -0
- package/ai-docs/templates/new-service/01-pre-questions.md +159 -0
- package/ai-docs/templates/new-service/02-code-generation.md +346 -0
- package/ai-docs/templates/new-service/03-integration.md +178 -0
- package/ai-docs/templates/new-service/04-test-generation.md +205 -0
- package/ai-docs/templates/new-service/05-validation.md +145 -0
- package/dist/cc.js +65 -123
- package/dist/cc.js.map +1 -1
- package/dist/constants.js +13 -2
- package/dist/constants.js.map +1 -1
- package/dist/index.js +13 -5
- package/dist/index.js.map +1 -1
- package/dist/metrics/behavioral-events.js +26 -13
- package/dist/metrics/behavioral-events.js.map +1 -1
- package/dist/metrics/constants.js +7 -6
- package/dist/metrics/constants.js.map +1 -1
- package/dist/services/ApiAiAssistant.js +0 -3
- package/dist/services/ApiAiAssistant.js.map +1 -1
- package/dist/services/config/Util.js +2 -3
- package/dist/services/config/Util.js.map +1 -1
- package/dist/services/config/types.js +16 -14
- package/dist/services/config/types.js.map +1 -1
- package/dist/services/constants.js +0 -1
- package/dist/services/constants.js.map +1 -1
- package/dist/services/core/Err.js.map +1 -1
- package/dist/services/core/Utils.js +79 -55
- package/dist/services/core/Utils.js.map +1 -1
- package/dist/services/core/aqm-reqs.js +17 -92
- package/dist/services/core/aqm-reqs.js.map +1 -1
- package/dist/services/core/websocket/WebSocketManager.js +5 -25
- package/dist/services/core/websocket/WebSocketManager.js.map +1 -1
- package/dist/services/core/websocket/types.js.map +1 -1
- package/dist/services/index.js +1 -2
- package/dist/services/index.js.map +1 -1
- package/dist/services/task/Task.js +644 -0
- package/dist/services/task/Task.js.map +1 -0
- package/dist/services/task/TaskFactory.js +45 -0
- package/dist/services/task/TaskFactory.js.map +1 -0
- package/dist/services/task/TaskManager.js +570 -535
- package/dist/services/task/TaskManager.js.map +1 -1
- package/dist/services/task/TaskUtils.js +132 -28
- package/dist/services/task/TaskUtils.js.map +1 -1
- package/dist/services/task/constants.js +7 -6
- package/dist/services/task/constants.js.map +1 -1
- package/dist/services/task/dialer.js +0 -51
- package/dist/services/task/dialer.js.map +1 -1
- package/dist/services/task/digital/Digital.js +77 -0
- package/dist/services/task/digital/Digital.js.map +1 -0
- package/dist/services/task/state-machine/TaskStateMachine.js +634 -0
- package/dist/services/task/state-machine/TaskStateMachine.js.map +1 -0
- package/dist/services/task/state-machine/actions.js +372 -0
- package/dist/services/task/state-machine/actions.js.map +1 -0
- package/dist/services/task/state-machine/constants.js +139 -0
- package/dist/services/task/state-machine/constants.js.map +1 -0
- package/dist/services/task/state-machine/guards.js +263 -0
- package/dist/services/task/state-machine/guards.js.map +1 -0
- package/dist/services/task/state-machine/index.js +53 -0
- package/dist/services/task/state-machine/index.js.map +1 -0
- package/dist/services/task/state-machine/types.js +54 -0
- package/dist/services/task/state-machine/types.js.map +1 -0
- package/dist/services/task/state-machine/uiControlsComputer.js +377 -0
- package/dist/services/task/state-machine/uiControlsComputer.js.map +1 -0
- package/dist/services/task/taskDataNormalizer.js +99 -0
- package/dist/services/task/taskDataNormalizer.js.map +1 -0
- package/dist/services/task/types.js +157 -18
- package/dist/services/task/types.js.map +1 -1
- package/dist/services/task/voice/Voice.js +1031 -0
- package/dist/services/task/voice/Voice.js.map +1 -0
- package/dist/services/task/voice/WebRTC.js +149 -0
- package/dist/services/task/voice/WebRTC.js.map +1 -0
- package/dist/types/cc.d.ts +4 -33
- package/dist/types/constants.d.ts +13 -2
- package/dist/types/index.d.ts +11 -5
- package/dist/types/metrics/constants.d.ts +5 -3
- package/dist/types/services/ApiAiAssistant.d.ts +1 -1
- package/dist/types/services/config/types.d.ts +97 -25
- package/dist/types/services/core/Err.d.ts +0 -2
- package/dist/types/services/core/Utils.d.ts +25 -23
- package/dist/types/services/core/aqm-reqs.d.ts +0 -49
- package/dist/types/services/core/websocket/WebSocketManager.d.ts +1 -1
- package/dist/types/services/core/websocket/connection-service.d.ts +0 -1
- package/dist/types/services/core/websocket/types.d.ts +1 -1
- package/dist/types/services/index.d.ts +1 -1
- package/dist/types/services/task/Task.d.ts +146 -0
- package/dist/types/services/task/TaskFactory.d.ts +12 -0
- package/dist/types/services/task/TaskUtils.d.ts +39 -8
- package/dist/types/services/task/constants.d.ts +5 -4
- package/dist/types/services/task/dialer.d.ts +0 -15
- package/dist/types/services/task/digital/Digital.d.ts +22 -0
- package/dist/types/services/task/state-machine/TaskStateMachine.d.ts +906 -0
- package/dist/types/services/task/state-machine/actions.d.ts +8 -0
- package/dist/types/services/task/state-machine/constants.d.ts +91 -0
- package/dist/types/services/task/state-machine/guards.d.ts +78 -0
- package/dist/types/services/task/state-machine/index.d.ts +13 -0
- package/dist/types/services/task/state-machine/types.d.ts +256 -0
- package/dist/types/services/task/state-machine/uiControlsComputer.d.ts +9 -0
- package/dist/types/services/task/taskDataNormalizer.d.ts +10 -0
- package/dist/types/services/task/types.d.ts +539 -88
- package/dist/types/services/task/voice/Voice.d.ts +183 -0
- package/dist/types/services/task/voice/WebRTC.d.ts +53 -0
- package/dist/types/types.d.ts +68 -0
- package/dist/types/webex.d.ts +1 -0
- package/dist/types.js +70 -0
- package/dist/types.js.map +1 -1
- package/dist/webex.js +14 -2
- package/dist/webex.js.map +1 -1
- package/package.json +14 -11
- package/src/cc.ts +91 -177
- package/src/constants.ts +13 -2
- package/src/index.ts +14 -5
- package/src/metrics/ai-docs/AGENTS.md +348 -0
- package/src/metrics/ai-docs/ARCHITECTURE.md +336 -0
- package/src/metrics/behavioral-events.ts +28 -14
- package/src/metrics/constants.ts +7 -8
- package/src/services/ApiAiAssistant.ts +2 -4
- package/src/services/agent/ai-docs/AGENTS.md +238 -0
- package/src/services/agent/ai-docs/ARCHITECTURE.md +302 -0
- package/src/services/ai-docs/AGENTS.md +384 -0
- package/src/services/config/Util.ts +2 -3
- package/src/services/config/ai-docs/AGENTS.md +253 -0
- package/src/services/config/ai-docs/ARCHITECTURE.md +424 -0
- package/src/services/config/types.ts +108 -20
- package/src/services/constants.ts +0 -1
- package/src/services/core/Err.ts +0 -1
- package/src/services/core/Utils.ts +90 -67
- package/src/services/core/ai-docs/AGENTS.md +379 -0
- package/src/services/core/ai-docs/ARCHITECTURE.md +696 -0
- package/src/services/core/aqm-reqs.ts +22 -100
- package/src/services/core/websocket/WebSocketManager.ts +4 -23
- package/src/services/core/websocket/types.ts +1 -1
- package/src/services/index.ts +1 -2
- package/src/services/task/Task.ts +785 -0
- package/src/services/task/TaskFactory.ts +55 -0
- package/src/services/task/TaskManager.ts +579 -633
- package/src/services/task/TaskUtils.ts +175 -31
- package/src/services/task/ai-docs/AGENTS.md +448 -0
- package/src/services/task/ai-docs/ARCHITECTURE.md +573 -0
- package/src/services/task/constants.ts +5 -4
- package/src/services/task/dialer.ts +1 -56
- package/src/services/task/digital/Digital.ts +95 -0
- package/src/services/task/state-machine/TaskStateMachine.ts +793 -0
- package/src/services/task/state-machine/actions.ts +422 -0
- package/src/services/task/state-machine/ai-docs/AGENTS.md +495 -0
- package/src/services/task/state-machine/ai-docs/ARCHITECTURE.md +1135 -0
- package/src/services/task/state-machine/constants.ts +150 -0
- package/src/services/task/state-machine/guards.ts +303 -0
- package/src/services/task/state-machine/index.ts +28 -0
- package/src/services/task/state-machine/types.ts +228 -0
- package/src/services/task/state-machine/uiControlsComputer.ts +542 -0
- package/src/services/task/taskDataNormalizer.ts +137 -0
- package/src/services/task/types.ts +641 -95
- package/src/services/task/voice/Voice.ts +1255 -0
- package/src/services/task/voice/WebRTC.ts +187 -0
- package/src/types.ts +88 -5
- package/src/utils/AGENTS.md +276 -0
- package/src/webex.js +2 -0
- package/test/unit/spec/cc.ts +59 -142
- package/test/unit/spec/logger-proxy.ts +70 -0
- package/test/unit/spec/services/ApiAiAssistant.ts +17 -0
- package/test/unit/spec/services/config/index.ts +26 -55
- package/test/unit/spec/services/core/Utils.ts +103 -52
- package/test/unit/spec/services/core/websocket/WebSocketManager.ts +48 -112
- package/test/unit/spec/services/core/websocket/connection-service.ts +5 -4
- package/test/unit/spec/services/task/AutoWrapup.ts +63 -0
- package/test/unit/spec/services/task/Task.ts +416 -0
- package/test/unit/spec/services/task/TaskFactory.ts +62 -0
- package/test/unit/spec/services/task/TaskManager.ts +781 -1735
- package/test/unit/spec/services/task/TaskUtils.ts +125 -0
- package/test/unit/spec/services/task/dialer.ts +112 -198
- package/test/unit/spec/services/task/digital/Digital.ts +105 -0
- package/test/unit/spec/services/task/state-machine/TaskStateMachine.ts +473 -0
- package/test/unit/spec/services/task/state-machine/guards.ts +288 -0
- package/test/unit/spec/services/task/state-machine/types.ts +18 -0
- package/test/unit/spec/services/task/state-machine/uiControlsComputer.ts +147 -0
- package/test/unit/spec/services/task/taskTestUtils.ts +87 -0
- package/test/unit/spec/services/task/voice/Voice.ts +587 -0
- package/test/unit/spec/services/task/voice/WebRTC.ts +242 -0
- package/umd/contact-center.min.js +2 -2
- package/umd/contact-center.min.js.map +1 -1
- package/dist/services/task/index.js +0 -1525
- package/dist/services/task/index.js.map +0 -1
- package/dist/types/services/task/index.d.ts +0 -650
- package/src/services/task/index.ts +0 -1801
- 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
|