@webex/contact-center 3.12.0-task-refactor.11 → 3.12.0-task-refactor.13
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/dist/cc.js +297 -83
- package/dist/cc.js.map +1 -1
- package/dist/constants.js +3 -0
- package/dist/constants.js.map +1 -1
- package/dist/metrics/behavioral-events.js +39 -0
- package/dist/metrics/behavioral-events.js.map +1 -1
- package/dist/metrics/constants.js +8 -1
- package/dist/metrics/constants.js.map +1 -1
- package/dist/services/ApiAiAssistant.js +3 -0
- package/dist/services/ApiAiAssistant.js.map +1 -1
- package/dist/services/config/Util.js +1 -1
- package/dist/services/config/Util.js.map +1 -1
- package/dist/services/config/types.js +10 -0
- package/dist/services/config/types.js.map +1 -1
- package/dist/services/constants.js +1 -0
- package/dist/services/constants.js.map +1 -1
- package/dist/services/core/Err.js.map +1 -1
- package/dist/services/core/Utils.js +57 -6
- package/dist/services/core/Utils.js.map +1 -1
- package/dist/services/core/aqm-reqs.js +92 -17
- package/dist/services/core/aqm-reqs.js.map +1 -1
- package/dist/services/core/websocket/WebSocketManager.js +24 -3
- package/dist/services/core/websocket/WebSocketManager.js.map +1 -1
- package/dist/services/index.js +1 -0
- package/dist/services/index.js.map +1 -1
- package/dist/services/task/Task.js +6 -0
- package/dist/services/task/Task.js.map +1 -1
- package/dist/services/task/TaskManager.js +155 -6
- package/dist/services/task/TaskManager.js.map +1 -1
- package/dist/services/task/TaskUtils.js +39 -11
- package/dist/services/task/TaskUtils.js.map +1 -1
- package/dist/services/task/constants.js +7 -1
- package/dist/services/task/constants.js.map +1 -1
- package/dist/services/task/dialer.js +129 -0
- package/dist/services/task/dialer.js.map +1 -1
- package/dist/services/task/state-machine/TaskStateMachine.js +30 -3
- package/dist/services/task/state-machine/TaskStateMachine.js.map +1 -1
- package/dist/services/task/state-machine/actions.js +4 -0
- package/dist/services/task/state-machine/actions.js.map +1 -1
- package/dist/services/task/state-machine/constants.js +3 -0
- package/dist/services/task/state-machine/constants.js.map +1 -1
- package/dist/services/task/state-machine/guards.js +23 -0
- package/dist/services/task/state-machine/guards.js.map +1 -1
- package/dist/services/task/state-machine/types.js.map +1 -1
- package/dist/services/task/types.js +59 -0
- package/dist/services/task/types.js.map +1 -1
- package/dist/types/cc.d.ts +76 -2
- package/dist/types/constants.d.ts +3 -0
- package/dist/types/metrics/constants.d.ts +6 -0
- package/dist/types/services/config/types.d.ts +22 -1
- package/dist/types/services/core/Err.d.ts +6 -0
- package/dist/types/services/core/Utils.d.ts +20 -2
- package/dist/types/services/core/aqm-reqs.d.ts +49 -0
- package/dist/types/services/core/websocket/WebSocketManager.d.ts +1 -0
- package/dist/types/services/core/websocket/connection-service.d.ts +1 -0
- package/dist/types/services/task/Task.d.ts +1 -0
- package/dist/types/services/task/TaskUtils.d.ts +13 -0
- package/dist/types/services/task/constants.d.ts +6 -0
- package/dist/types/services/task/dialer.d.ts +45 -0
- package/dist/types/services/task/state-machine/TaskStateMachine.d.ts +36 -8
- package/dist/types/services/task/state-machine/constants.d.ts +3 -0
- package/dist/types/services/task/state-machine/guards.d.ts +2 -0
- package/dist/types/services/task/state-machine/types.d.ts +11 -0
- package/dist/types/services/task/types.d.ts +75 -1
- package/dist/types.js.map +1 -1
- package/dist/webex.js +1 -1
- package/package.json +2 -2
- package/src/cc.ts +389 -111
- package/src/constants.ts +3 -0
- package/src/metrics/behavioral-events.ts +42 -0
- package/src/metrics/constants.ts +9 -1
- package/src/services/ApiAiAssistant.ts +3 -0
- package/src/services/config/Util.ts +1 -1
- package/src/services/config/types.ts +12 -1
- package/src/services/constants.ts +1 -0
- package/src/services/core/Err.ts +3 -0
- package/src/services/core/Utils.ts +68 -5
- package/src/services/core/aqm-reqs.ts +100 -22
- package/src/services/core/websocket/WebSocketManager.ts +23 -2
- package/src/services/index.ts +1 -0
- package/src/services/task/Task.ts +13 -0
- package/src/services/task/TaskManager.ts +171 -7
- package/src/services/task/TaskUtils.ts +33 -1
- package/src/services/task/constants.ts +6 -0
- package/src/services/task/dialer.ts +136 -1
- package/src/services/task/state-machine/TaskStateMachine.ts +37 -5
- package/src/services/task/state-machine/actions.ts +4 -0
- package/src/services/task/state-machine/constants.ts +3 -0
- package/src/services/task/state-machine/guards.ts +30 -0
- package/src/services/task/state-machine/types.ts +14 -1
- package/src/services/task/types.ts +80 -0
- package/src/types.ts +4 -1
- package/test/unit/spec/cc.ts +294 -32
- package/test/unit/spec/services/config/index.ts +30 -2
- package/test/unit/spec/services/core/Utils.ts +367 -1
- package/test/unit/spec/services/core/websocket/WebSocketManager.ts +91 -1
- package/test/unit/spec/services/core/websocket/connection-service.ts +4 -5
- package/test/unit/spec/services/task/TaskManager.ts +4 -2
- package/test/unit/spec/services/task/dialer.ts +372 -96
- package/umd/contact-center.min.js +2 -2
- package/umd/contact-center.min.js.map +1 -1
package/dist/cc.js
CHANGED
|
@@ -85,6 +85,7 @@ function _interopRequireDefault(e) { return e && e.__esModule ? e : { default: e
|
|
|
85
85
|
* - `task:established` - Task/call has been connected
|
|
86
86
|
* - `task:ended` - Task/call has ended
|
|
87
87
|
* - `task:error` - An error occurred during task handling
|
|
88
|
+
* - `task:campaignPreviewReservation` - Campaign preview contact offered to agent
|
|
88
89
|
*
|
|
89
90
|
* @public
|
|
90
91
|
*
|
|
@@ -312,7 +313,6 @@ class ContactCenter extends _webexCore.WebexPlugin {
|
|
|
312
313
|
webex: this.$webex,
|
|
313
314
|
connectionConfig: this.getConnectionConfig()
|
|
314
315
|
});
|
|
315
|
-
this.services.webSocketManager.on('message', this.handleWebsocketMessage);
|
|
316
316
|
this.webCallingService = new _WebCallingService.default(this.$webex);
|
|
317
317
|
this.apiAIAssistant = new _ApiAiAssistant.ApiAIAssistant(this.$webex);
|
|
318
318
|
this.metricsManager = _MetricsManager.default.getInstance({
|
|
@@ -370,6 +370,19 @@ class ContactCenter extends _webexCore.WebexPlugin {
|
|
|
370
370
|
this.trigger(_types4.TASK_EVENTS.TASK_MERGED, task);
|
|
371
371
|
};
|
|
372
372
|
|
|
373
|
+
/**
|
|
374
|
+
* Handles campaign preview reservation events when a contact is offered to the agent
|
|
375
|
+
* @private
|
|
376
|
+
* @param {ITask} task The campaign reservation task
|
|
377
|
+
*/
|
|
378
|
+
handleCampaignPreviewReservation = task => {
|
|
379
|
+
// @ts-ignore
|
|
380
|
+
this.trigger(_types4.TASK_EVENTS.TASK_CAMPAIGN_PREVIEW_RESERVATION, task);
|
|
381
|
+
};
|
|
382
|
+
handleRTDWebsocketMessage = event => {
|
|
383
|
+
this.taskManager.handleRealtimeWebsocketEvent(event);
|
|
384
|
+
};
|
|
385
|
+
|
|
373
386
|
/**
|
|
374
387
|
* Sets up event listeners for incoming tasks and task hydration
|
|
375
388
|
* Subscribes to task events from the task manager
|
|
@@ -380,6 +393,7 @@ class ContactCenter extends _webexCore.WebexPlugin {
|
|
|
380
393
|
this.taskManager.on(_types4.TASK_EVENTS.TASK_HYDRATE, this.handleTaskHydrate);
|
|
381
394
|
this.taskManager.on(_types4.TASK_EVENTS.TASK_MULTI_LOGIN_HYDRATE, this.handleTaskMultiLoginHydrate);
|
|
382
395
|
this.taskManager.on(_types4.TASK_EVENTS.TASK_MERGED, this.handleTaskMerged);
|
|
396
|
+
this.taskManager.on(_types4.TASK_EVENTS.TASK_CAMPAIGN_PREVIEW_RESERVATION, this.handleCampaignPreviewReservation);
|
|
383
397
|
}
|
|
384
398
|
|
|
385
399
|
/**
|
|
@@ -419,13 +433,14 @@ class ContactCenter extends _webexCore.WebexPlugin {
|
|
|
419
433
|
* ```
|
|
420
434
|
*/
|
|
421
435
|
async register() {
|
|
422
|
-
_loggerProxy.default.
|
|
436
|
+
_loggerProxy.default.log('Starting CC SDK registration', {
|
|
423
437
|
module: _constants.CC_FILE,
|
|
424
438
|
method: _constants.METHODS.REGISTER
|
|
425
439
|
});
|
|
426
440
|
try {
|
|
427
441
|
this.metricsManager.timeEvent([_constants4.METRIC_EVENT_NAMES.WEBSOCKET_REGISTER_SUCCESS, _constants4.METRIC_EVENT_NAMES.WEBSOCKET_REGISTER_FAILED]);
|
|
428
442
|
this.setupEventListeners();
|
|
443
|
+
this.services.webSocketManager.on('message', this.handleWebsocketMessage);
|
|
429
444
|
const resp = await this.connectWebsocket();
|
|
430
445
|
// Ensure 'dn' is always populated from 'defaultDn'
|
|
431
446
|
resp.dn = resp.defaultDn;
|
|
@@ -489,6 +504,7 @@ class ContactCenter extends _webexCore.WebexPlugin {
|
|
|
489
504
|
this.taskManager.off(_types4.TASK_EVENTS.TASK_INCOMING, this.handleIncomingTask);
|
|
490
505
|
this.taskManager.off(_types4.TASK_EVENTS.TASK_HYDRATE, this.handleTaskHydrate);
|
|
491
506
|
this.taskManager.off(_types4.TASK_EVENTS.TASK_MULTI_LOGIN_HYDRATE, this.handleTaskMultiLoginHydrate);
|
|
507
|
+
this.taskManager.off(_types4.TASK_EVENTS.TASK_CAMPAIGN_PREVIEW_RESERVATION, this.handleCampaignPreviewReservation);
|
|
492
508
|
this.taskManager.unregisterIncomingCallEvent();
|
|
493
509
|
this.services.webSocketManager.off('message', this.handleWebsocketMessage);
|
|
494
510
|
this.services.rtdWebSocketManager.off('message', this.handleRTDWebsocketMessage);
|
|
@@ -512,6 +528,9 @@ class ContactCenter extends _webexCore.WebexPlugin {
|
|
|
512
528
|
if (this.services.rtdWebSocketManager && !this.services.rtdWebSocketManager.isSocketClosed) {
|
|
513
529
|
this.services.rtdWebSocketManager.close(false, 'Unregistering the SDK');
|
|
514
530
|
}
|
|
531
|
+
if (this.services.rtdWebSocketManager && !this.services.rtdWebSocketManager.isSocketClosed) {
|
|
532
|
+
this.services.rtdWebSocketManager.close(false, 'Unregistering the RTD websocket');
|
|
533
|
+
}
|
|
515
534
|
|
|
516
535
|
// Clear any cached agent configuration
|
|
517
536
|
this.agentConfig = null;
|
|
@@ -613,85 +632,89 @@ class ContactCenter extends _webexCore.WebexPlugin {
|
|
|
613
632
|
* @private
|
|
614
633
|
*/
|
|
615
634
|
async connectWebsocket() {
|
|
616
|
-
_loggerProxy.default.
|
|
635
|
+
_loggerProxy.default.log('Connecting to websocket', {
|
|
617
636
|
module: _constants.CC_FILE,
|
|
618
637
|
method: _constants.METHODS.CONNECT_WEBSOCKET
|
|
619
638
|
});
|
|
620
639
|
try {
|
|
621
|
-
|
|
640
|
+
const data = await this.services.webSocketManager.initWebSocket({
|
|
622
641
|
body: this.getConnectionConfig(),
|
|
623
642
|
resource: _constants3.SUBSCRIBE_API
|
|
624
|
-
})
|
|
625
|
-
|
|
626
|
-
|
|
627
|
-
|
|
628
|
-
|
|
643
|
+
});
|
|
644
|
+
const agentId = data.agentId;
|
|
645
|
+
const orgId = this.$webex.credentials.getOrgId();
|
|
646
|
+
this.agentConfig = await this.services.config.getAgentConfig(orgId, agentId);
|
|
647
|
+
_loggerProxy.default.log(`Agent config is fetched successfully`, {
|
|
648
|
+
module: _constants.CC_FILE,
|
|
649
|
+
method: _constants.METHODS.CONNECT_WEBSOCKET
|
|
650
|
+
});
|
|
651
|
+
const configFlags = {
|
|
652
|
+
isEndTaskEnabled: this.agentConfig.isEndTaskEnabled,
|
|
653
|
+
isEndConsultEnabled: this.agentConfig.isEndConsultEnabled,
|
|
654
|
+
webRtcEnabled: this.agentConfig.webRtcEnabled,
|
|
655
|
+
autoWrapup: this.agentConfig.wrapUpData?.wrapUpProps?.autoWrapup ?? false,
|
|
656
|
+
aiFeature: this.agentConfig.aiFeature
|
|
657
|
+
};
|
|
658
|
+
this.taskManager.setConfigFlags(configFlags);
|
|
659
|
+
// TODO: Make profile a singleton to make it available throughout app/sdk so we dont need to inject info everywhere
|
|
660
|
+
this.taskManager.setWrapupData(this.agentConfig.wrapUpData);
|
|
661
|
+
this.taskManager.setAgentId(this.agentConfig.agentId);
|
|
662
|
+
this.taskManager.setWebRtcEnabled(this.agentConfig.webRtcEnabled);
|
|
663
|
+
this.apiAIAssistant.setAIFeatureFlags(this.agentConfig.aiFeature);
|
|
664
|
+
|
|
665
|
+
/**
|
|
666
|
+
* RTD websocket currently supports realtime transcripts and suggested responses.
|
|
667
|
+
* Extend this condition when additional AI RTD features are introduced.
|
|
668
|
+
*/
|
|
669
|
+
if (this.agentConfig.aiFeature?.realtimeTranscripts?.enable || this.agentConfig.aiFeature?.suggestedResponses?.enable) {
|
|
670
|
+
_loggerProxy.default.info('Connecting to RTD websocket', {
|
|
629
671
|
module: _constants.CC_FILE,
|
|
630
672
|
method: _constants.METHODS.CONNECT_WEBSOCKET
|
|
631
673
|
});
|
|
632
|
-
|
|
633
|
-
|
|
634
|
-
|
|
635
|
-
|
|
636
|
-
|
|
637
|
-
aiFeature: this.agentConfig.aiFeature
|
|
638
|
-
};
|
|
639
|
-
this.taskManager.setConfigFlags(configFlags);
|
|
640
|
-
// TODO: Make profile a singleton to make it available throughout app/sdk so we dont need to inject info everywhere
|
|
641
|
-
this.taskManager.setWrapupData(this.agentConfig.wrapUpData);
|
|
642
|
-
this.taskManager.setAgentId(this.agentConfig.agentId);
|
|
643
|
-
this.taskManager.setWebRtcEnabled(this.agentConfig.webRtcEnabled);
|
|
644
|
-
this.apiAIAssistant.setAIFeatureFlags(this.agentConfig.aiFeature);
|
|
645
|
-
/**
|
|
646
|
-
* RTD websocket currently supports realtime transcripts and suggested responses.
|
|
647
|
-
* Extend this condition when additional AI RTD features are introduced.
|
|
648
|
-
*/
|
|
649
|
-
if (this.agentConfig.aiFeature?.realtimeTranscripts?.enable || this.agentConfig.aiFeature?.suggestedResponses?.enable) {
|
|
650
|
-
_loggerProxy.default.info('Connecting to RTD websocket', {
|
|
674
|
+
this.services.rtdWebSocketManager.initWebSocket({
|
|
675
|
+
body: this.getConnectionConfig(),
|
|
676
|
+
resource: _constants3.RTD_SUBSCRIBE_API
|
|
677
|
+
}).then(() => {
|
|
678
|
+
_loggerProxy.default.log('RTD websocket connected successfully', {
|
|
651
679
|
module: _constants.CC_FILE,
|
|
652
680
|
method: _constants.METHODS.CONNECT_WEBSOCKET
|
|
653
681
|
});
|
|
654
|
-
this.services.rtdWebSocketManager.
|
|
655
|
-
|
|
656
|
-
|
|
657
|
-
|
|
658
|
-
|
|
659
|
-
module: _constants.CC_FILE,
|
|
660
|
-
method: _constants.METHODS.CONNECT_WEBSOCKET
|
|
661
|
-
});
|
|
662
|
-
this.services.rtdWebSocketManager.on('message', this.handleRTDWebsocketMessage);
|
|
663
|
-
}).catch(error => {
|
|
664
|
-
_loggerProxy.default.error(`Error connecting to RTD websocket ${error}`, {
|
|
665
|
-
module: _constants.CC_FILE,
|
|
666
|
-
method: _constants.METHODS.CONNECT_WEBSOCKET
|
|
667
|
-
});
|
|
682
|
+
this.services.rtdWebSocketManager.on('message', this.handleRTDWebsocketMessage);
|
|
683
|
+
}).catch(error => {
|
|
684
|
+
_loggerProxy.default.error(`Error connecting to RTD websocket ${error}`, {
|
|
685
|
+
module: _constants.CC_FILE,
|
|
686
|
+
method: _constants.METHODS.CONNECT_WEBSOCKET
|
|
668
687
|
});
|
|
669
|
-
}
|
|
670
|
-
|
|
671
|
-
|
|
672
|
-
|
|
673
|
-
|
|
674
|
-
|
|
675
|
-
|
|
676
|
-
|
|
677
|
-
_loggerProxy.default.error(`Error occurred during mercury.connect() ${error}`, {
|
|
678
|
-
module: _constants.CC_FILE,
|
|
679
|
-
method: _constants.METHODS.CONNECT_WEBSOCKET
|
|
680
|
-
});
|
|
688
|
+
});
|
|
689
|
+
}
|
|
690
|
+
if (this.agentConfig.webRtcEnabled && this.agentConfig.loginVoiceOptions.includes(_types.LoginOption.BROWSER) && !this.isWebRTCRegistrationDisabled()) {
|
|
691
|
+
try {
|
|
692
|
+
await this.$webex.internal.mercury.connect();
|
|
693
|
+
_loggerProxy.default.log('Authentication: webex.internal.mercury.connect successful', {
|
|
694
|
+
module: _constants.CC_FILE,
|
|
695
|
+
method: _constants.METHODS.CONNECT_WEBSOCKET
|
|
681
696
|
});
|
|
682
|
-
}
|
|
683
|
-
_loggerProxy.default.
|
|
697
|
+
} catch (error) {
|
|
698
|
+
_loggerProxy.default.error(`Error occurred during mercury.connect() ${error}`, {
|
|
684
699
|
module: _constants.CC_FILE,
|
|
685
700
|
method: _constants.METHODS.CONNECT_WEBSOCKET
|
|
686
701
|
});
|
|
687
702
|
}
|
|
688
|
-
|
|
689
|
-
|
|
690
|
-
|
|
691
|
-
|
|
692
|
-
|
|
693
|
-
|
|
694
|
-
|
|
703
|
+
} else if (this.isWebRTCRegistrationDisabled()) {
|
|
704
|
+
_loggerProxy.default.info('Skipping Mobius registration because disableWebRTCRegistration is enabled', {
|
|
705
|
+
module: _constants.CC_FILE,
|
|
706
|
+
method: _constants.METHODS.CONNECT_WEBSOCKET
|
|
707
|
+
});
|
|
708
|
+
}
|
|
709
|
+
if (this.$config && this.$config.allowAutomatedRelogin) {
|
|
710
|
+
await this.silentRelogin();
|
|
711
|
+
} else {
|
|
712
|
+
_loggerProxy.default.log('Skipping silent relogin: allowAutomatedRelogin is disabled', {
|
|
713
|
+
module: _constants.CC_FILE,
|
|
714
|
+
method: _constants.METHODS.CONNECT_WEBSOCKET
|
|
715
|
+
});
|
|
716
|
+
}
|
|
717
|
+
return this.agentConfig;
|
|
695
718
|
} catch (error) {
|
|
696
719
|
_loggerProxy.default.error(`Error during register: ${error}`, {
|
|
697
720
|
module: _constants.CC_FILE,
|
|
@@ -730,21 +753,27 @@ class ContactCenter extends _webexCore.WebexPlugin {
|
|
|
730
753
|
* ```
|
|
731
754
|
*/
|
|
732
755
|
async stationLogin(data) {
|
|
733
|
-
|
|
756
|
+
const loggerContext = {
|
|
734
757
|
module: _constants.CC_FILE,
|
|
735
758
|
method: _constants.METHODS.STATION_LOGIN
|
|
736
|
-
}
|
|
759
|
+
};
|
|
737
760
|
try {
|
|
761
|
+
_loggerProxy.default.log(`Starting agent station login | loginOption: ${data?.loginOption} teamId: ${data?.teamId}`, loggerContext);
|
|
738
762
|
this.metricsManager.timeEvent([_constants4.METRIC_EVENT_NAMES.STATION_LOGIN_SUCCESS, _constants4.METRIC_EVENT_NAMES.STATION_LOGIN_FAILED]);
|
|
739
|
-
|
|
740
|
-
|
|
741
|
-
|
|
742
|
-
|
|
743
|
-
data: {
|
|
744
|
-
|
|
745
|
-
|
|
746
|
-
|
|
747
|
-
|
|
763
|
+
const dialPlanEntries = this.agentConfig?.dialPlan?.dialPlanEntity ?? [];
|
|
764
|
+
if (data.loginOption === _types.LoginOption.AGENT_DN) {
|
|
765
|
+
_loggerProxy.default.log(`Validating dial number | dialPlanEnabled: ${!!this.agentConfig?.dialPlan} | dialPlanEntryCount: ${dialPlanEntries.length}`, loggerContext);
|
|
766
|
+
if (!(0, _Utils.isValidDialNumber)(data.dialNumber, dialPlanEntries)) {
|
|
767
|
+
_loggerProxy.default.log(`Dial number validation failed | dialNumber: ${data.dialNumber} | dialPlanEntryCount: ${dialPlanEntries.length}`, loggerContext);
|
|
768
|
+
const error = new Error('INVALID_DIAL_NUMBER');
|
|
769
|
+
// @ts-ignore - adding custom key to the error object
|
|
770
|
+
error.details = {
|
|
771
|
+
data: {
|
|
772
|
+
reason: 'INVALID_DIAL_NUMBER'
|
|
773
|
+
}
|
|
774
|
+
};
|
|
775
|
+
throw error;
|
|
776
|
+
}
|
|
748
777
|
}
|
|
749
778
|
const loginResponse = await this.services.agent.stationLogin({
|
|
750
779
|
data: {
|
|
@@ -1089,9 +1118,6 @@ class ContactCenter extends _webexCore.WebexPlugin {
|
|
|
1089
1118
|
break;
|
|
1090
1119
|
}
|
|
1091
1120
|
};
|
|
1092
|
-
handleRTDWebsocketMessage = event => {
|
|
1093
|
-
this.taskManager.handleRealtimeWebsocketEvent(event);
|
|
1094
|
-
};
|
|
1095
1121
|
|
|
1096
1122
|
/**
|
|
1097
1123
|
* Checks whether Mobius/WebRTC registration should be skipped by config
|
|
@@ -1143,13 +1169,13 @@ class ContactCenter extends _webexCore.WebexPlugin {
|
|
|
1143
1169
|
async handleConnectionLost(msg) {
|
|
1144
1170
|
if (msg.isConnectionLost) {
|
|
1145
1171
|
// TODO: Emit an event saying connection is lost
|
|
1146
|
-
_loggerProxy.default.
|
|
1172
|
+
_loggerProxy.default.log('event=handleConnectionLost | Connection lost', {
|
|
1147
1173
|
module: _constants.CC_FILE,
|
|
1148
1174
|
method: _constants.METHODS.HANDLE_CONNECTION_LOST
|
|
1149
1175
|
});
|
|
1150
1176
|
} else if (msg.isSocketReconnected) {
|
|
1151
1177
|
// TODO: Emit an event saying connection is re-estabilished
|
|
1152
|
-
_loggerProxy.default.
|
|
1178
|
+
_loggerProxy.default.log('event=handleConnectionReconnect | Connection reconnected attempting to request silent relogin', {
|
|
1153
1179
|
module: _constants.CC_FILE,
|
|
1154
1180
|
method: _constants.METHODS.HANDLE_CONNECTION_LOST
|
|
1155
1181
|
});
|
|
@@ -1164,7 +1190,7 @@ class ContactCenter extends _webexCore.WebexPlugin {
|
|
|
1164
1190
|
* @private
|
|
1165
1191
|
*/
|
|
1166
1192
|
async silentRelogin() {
|
|
1167
|
-
_loggerProxy.default.
|
|
1193
|
+
_loggerProxy.default.log('Starting silent relogin process', {
|
|
1168
1194
|
module: _constants.CC_FILE,
|
|
1169
1195
|
method: _constants.METHODS.SILENT_RELOGIN
|
|
1170
1196
|
});
|
|
@@ -1186,7 +1212,7 @@ class ContactCenter extends _webexCore.WebexPlugin {
|
|
|
1186
1212
|
this.agentConfig.currentTeamId = reLoginResponse.data.teamId;
|
|
1187
1213
|
await this.handleDeviceType(deviceType, dn);
|
|
1188
1214
|
if (lastStateChangeReason === 'agent-wss-disconnect') {
|
|
1189
|
-
_loggerProxy.default.
|
|
1215
|
+
_loggerProxy.default.log('event=requestAutoStateChange | Requesting state change to available on socket reconnect', {
|
|
1190
1216
|
module: _constants.CC_FILE,
|
|
1191
1217
|
method: _constants.METHODS.SILENT_RELOGIN
|
|
1192
1218
|
});
|
|
@@ -1210,8 +1236,6 @@ class ContactCenter extends _webexCore.WebexPlugin {
|
|
|
1210
1236
|
}
|
|
1211
1237
|
this.agentConfig.lastStateAuxCodeId = auxCodeId;
|
|
1212
1238
|
this.agentConfig.isAgentLoggedIn = true;
|
|
1213
|
-
// TODO: https://jira-eng-gpk2.cisco.com/jira/browse/SPARK-626777 Implement the de-register method and close the listener there
|
|
1214
|
-
this.services.webSocketManager.on('message', this.handleWebsocketMessage);
|
|
1215
1239
|
_loggerProxy.default.log(`Silent relogin process completed successfully with login Option: ${reLoginResponse.data.deviceType} teamId: ${reLoginResponse.data.teamId}`, {
|
|
1216
1240
|
module: _constants.CC_FILE,
|
|
1217
1241
|
method: _constants.METHODS.SILENT_RELOGIN,
|
|
@@ -1434,6 +1458,196 @@ class ContactCenter extends _webexCore.WebexPlugin {
|
|
|
1434
1458
|
}
|
|
1435
1459
|
}
|
|
1436
1460
|
|
|
1461
|
+
/**
|
|
1462
|
+
* Accepts a campaign preview contact, initiating the outbound call.
|
|
1463
|
+
*
|
|
1464
|
+
* When a campaign manager reserves a contact for an agent, the agent receives an
|
|
1465
|
+
* `AgentOfferCampaignReservation` event. The agent can then accept the preview contact
|
|
1466
|
+
* to initiate the outbound call.
|
|
1467
|
+
*
|
|
1468
|
+
* @param {PreviewContactPayload} payload - The preview contact payload containing interactionId and campaignId (campaign name, not UUID).
|
|
1469
|
+
* @returns {Promise<TaskResponse>} Promise resolving with agent contact on success.
|
|
1470
|
+
* @throws {Error} If the operation fails (network error, customer unavailable, etc.)
|
|
1471
|
+
*
|
|
1472
|
+
* @example
|
|
1473
|
+
* ```typescript
|
|
1474
|
+
* webex.cc.on('task:campaignPreviewReservation', async (task) => {
|
|
1475
|
+
* const { interactionId } = task.data;
|
|
1476
|
+
* // campaignId is the campaign name (e.g. "MyCampaign"), not a UUID
|
|
1477
|
+
* const campaignId = task.data.interaction.callProcessingDetails.campaignId;
|
|
1478
|
+
*
|
|
1479
|
+
* const result = await webex.cc.acceptPreviewContact({ interactionId, campaignId });
|
|
1480
|
+
* });
|
|
1481
|
+
* ```
|
|
1482
|
+
*/
|
|
1483
|
+
async acceptPreviewContact(payload) {
|
|
1484
|
+
_loggerProxy.default.info('Accepting campaign preview contact', {
|
|
1485
|
+
module: _constants.CC_FILE,
|
|
1486
|
+
method: _constants.METHODS.ACCEPT_PREVIEW_CONTACT
|
|
1487
|
+
});
|
|
1488
|
+
try {
|
|
1489
|
+
this.metricsManager.timeEvent([_constants4.METRIC_EVENT_NAMES.CAMPAIGN_PREVIEW_ACCEPT_SUCCESS, _constants4.METRIC_EVENT_NAMES.CAMPAIGN_PREVIEW_ACCEPT_FAILED]);
|
|
1490
|
+
const result = await this.services.dialer.acceptPreviewContact({
|
|
1491
|
+
data: payload
|
|
1492
|
+
});
|
|
1493
|
+
this.metricsManager.trackEvent(_constants4.METRIC_EVENT_NAMES.CAMPAIGN_PREVIEW_ACCEPT_SUCCESS, {
|
|
1494
|
+
..._MetricsManager.default.getCommonTrackingFieldForAQMResponse(result),
|
|
1495
|
+
interactionId: payload.interactionId,
|
|
1496
|
+
campaignId: payload.campaignId
|
|
1497
|
+
}, ['behavioral', 'business', 'operational']);
|
|
1498
|
+
_loggerProxy.default.log('Campaign preview contact accepted successfully', {
|
|
1499
|
+
module: _constants.CC_FILE,
|
|
1500
|
+
method: _constants.METHODS.ACCEPT_PREVIEW_CONTACT,
|
|
1501
|
+
trackingId: result.trackingId,
|
|
1502
|
+
interactionId: payload.interactionId
|
|
1503
|
+
});
|
|
1504
|
+
return result;
|
|
1505
|
+
} catch (error) {
|
|
1506
|
+
const failure = error.details;
|
|
1507
|
+
this.metricsManager.trackEvent(_constants4.METRIC_EVENT_NAMES.CAMPAIGN_PREVIEW_ACCEPT_FAILED, {
|
|
1508
|
+
..._MetricsManager.default.getCommonTrackingFieldForAQMResponseFailed(failure),
|
|
1509
|
+
interactionId: payload.interactionId,
|
|
1510
|
+
campaignId: payload.campaignId
|
|
1511
|
+
}, ['behavioral', 'business', 'operational']);
|
|
1512
|
+
const {
|
|
1513
|
+
error: detailedError
|
|
1514
|
+
} = (0, _Utils.getErrorDetails)(error, _constants.METHODS.ACCEPT_PREVIEW_CONTACT, _constants.CC_FILE);
|
|
1515
|
+
throw detailedError;
|
|
1516
|
+
}
|
|
1517
|
+
}
|
|
1518
|
+
|
|
1519
|
+
/**
|
|
1520
|
+
* Skips a campaign preview contact, requesting the next contact from the campaign.
|
|
1521
|
+
*
|
|
1522
|
+
* When a campaign manager reserves a contact for an agent, the agent receives an
|
|
1523
|
+
* `AgentOfferCampaignReservation` event. Instead of accepting, the agent can skip the
|
|
1524
|
+
* preview contact to move to the next contact in the campaign.
|
|
1525
|
+
*
|
|
1526
|
+
* @param {PreviewContactPayload} payload - The preview contact payload containing interactionId and campaignId (campaign name, not UUID).
|
|
1527
|
+
* @returns {Promise<TaskResponse>} Promise resolving with agent contact on success.
|
|
1528
|
+
* @throws {Error} If the operation fails (network error, etc.)
|
|
1529
|
+
*
|
|
1530
|
+
* @example
|
|
1531
|
+
* ```typescript
|
|
1532
|
+
* webex.cc.on('task:campaignPreviewReservation', async (task) => {
|
|
1533
|
+
* const { interactionId } = task.data;
|
|
1534
|
+
* const campaignId = task.data.interaction.callProcessingDetails.campaignId;
|
|
1535
|
+
*
|
|
1536
|
+
* const result = await webex.cc.skipPreviewContact({ interactionId, campaignId });
|
|
1537
|
+
* });
|
|
1538
|
+
* ```
|
|
1539
|
+
*/
|
|
1540
|
+
async skipPreviewContact(payload) {
|
|
1541
|
+
const task = this.taskManager.getTask(payload.interactionId);
|
|
1542
|
+
if (task?.data?.interaction?.callProcessingDetails?.campaignPreviewSkipDisabled === 'true') {
|
|
1543
|
+
_loggerProxy.default.warn('Skip action is disabled for this campaign preview contact', {
|
|
1544
|
+
module: _constants.CC_FILE,
|
|
1545
|
+
method: _constants.METHODS.SKIP_PREVIEW_CONTACT,
|
|
1546
|
+
interactionId: payload.interactionId
|
|
1547
|
+
});
|
|
1548
|
+
throw new Error('Skip action is disabled for this campaign preview contact');
|
|
1549
|
+
}
|
|
1550
|
+
_loggerProxy.default.info('Skipping campaign preview contact', {
|
|
1551
|
+
module: _constants.CC_FILE,
|
|
1552
|
+
method: _constants.METHODS.SKIP_PREVIEW_CONTACT
|
|
1553
|
+
});
|
|
1554
|
+
try {
|
|
1555
|
+
this.metricsManager.timeEvent([_constants4.METRIC_EVENT_NAMES.CAMPAIGN_PREVIEW_SKIP_SUCCESS, _constants4.METRIC_EVENT_NAMES.CAMPAIGN_PREVIEW_SKIP_FAILED]);
|
|
1556
|
+
const result = await this.services.dialer.skipPreviewContact({
|
|
1557
|
+
data: payload
|
|
1558
|
+
});
|
|
1559
|
+
this.metricsManager.trackEvent(_constants4.METRIC_EVENT_NAMES.CAMPAIGN_PREVIEW_SKIP_SUCCESS, {
|
|
1560
|
+
..._MetricsManager.default.getCommonTrackingFieldForAQMResponse(result),
|
|
1561
|
+
interactionId: payload.interactionId,
|
|
1562
|
+
campaignId: payload.campaignId
|
|
1563
|
+
}, ['behavioral', 'business', 'operational']);
|
|
1564
|
+
_loggerProxy.default.log('Campaign preview contact skipped successfully', {
|
|
1565
|
+
module: _constants.CC_FILE,
|
|
1566
|
+
method: _constants.METHODS.SKIP_PREVIEW_CONTACT,
|
|
1567
|
+
trackingId: result.trackingId,
|
|
1568
|
+
interactionId: payload.interactionId
|
|
1569
|
+
});
|
|
1570
|
+
return result;
|
|
1571
|
+
} catch (error) {
|
|
1572
|
+
const failure = error.details;
|
|
1573
|
+
this.metricsManager.trackEvent(_constants4.METRIC_EVENT_NAMES.CAMPAIGN_PREVIEW_SKIP_FAILED, {
|
|
1574
|
+
..._MetricsManager.default.getCommonTrackingFieldForAQMResponseFailed(failure),
|
|
1575
|
+
interactionId: payload.interactionId,
|
|
1576
|
+
campaignId: payload.campaignId
|
|
1577
|
+
}, ['behavioral', 'business', 'operational']);
|
|
1578
|
+
const {
|
|
1579
|
+
error: detailedError
|
|
1580
|
+
} = (0, _Utils.getErrorDetails)(error, _constants.METHODS.SKIP_PREVIEW_CONTACT, _constants.CC_FILE);
|
|
1581
|
+
throw detailedError;
|
|
1582
|
+
}
|
|
1583
|
+
}
|
|
1584
|
+
|
|
1585
|
+
/**
|
|
1586
|
+
* Removes a campaign preview contact from the campaign list entirely.
|
|
1587
|
+
*
|
|
1588
|
+
* When a campaign manager reserves a contact for an agent, the agent receives an
|
|
1589
|
+
* `AgentOfferCampaignReservation` event. Instead of accepting or skipping, the agent can
|
|
1590
|
+
* remove the preview contact to permanently take it out of the campaign contact list.
|
|
1591
|
+
*
|
|
1592
|
+
* @param {PreviewContactPayload} payload - The preview contact payload containing interactionId and campaignId (campaign name, not UUID).
|
|
1593
|
+
* @returns {Promise<TaskResponse>} Promise resolving with agent contact on success.
|
|
1594
|
+
* @throws {Error} If the operation fails (network error, etc.)
|
|
1595
|
+
*
|
|
1596
|
+
* @example
|
|
1597
|
+
* ```typescript
|
|
1598
|
+
* webex.cc.on('task:campaignPreviewReservation', async (task) => {
|
|
1599
|
+
* const { interactionId } = task.data;
|
|
1600
|
+
* const campaignId = task.data.interaction.callProcessingDetails.campaignId;
|
|
1601
|
+
*
|
|
1602
|
+
* const result = await webex.cc.removePreviewContact({ interactionId, campaignId });
|
|
1603
|
+
* });
|
|
1604
|
+
* ```
|
|
1605
|
+
*/
|
|
1606
|
+
async removePreviewContact(payload) {
|
|
1607
|
+
const task = this.taskManager.getTask(payload.interactionId);
|
|
1608
|
+
if (task?.data?.interaction?.callProcessingDetails?.campaignPreviewRemoveDisabled === 'true') {
|
|
1609
|
+
_loggerProxy.default.warn('Remove action is disabled for this campaign preview contact', {
|
|
1610
|
+
module: _constants.CC_FILE,
|
|
1611
|
+
method: _constants.METHODS.REMOVE_PREVIEW_CONTACT,
|
|
1612
|
+
interactionId: payload.interactionId
|
|
1613
|
+
});
|
|
1614
|
+
throw new Error('Remove action is disabled for this campaign preview contact');
|
|
1615
|
+
}
|
|
1616
|
+
_loggerProxy.default.info('Removing campaign preview contact', {
|
|
1617
|
+
module: _constants.CC_FILE,
|
|
1618
|
+
method: _constants.METHODS.REMOVE_PREVIEW_CONTACT
|
|
1619
|
+
});
|
|
1620
|
+
try {
|
|
1621
|
+
this.metricsManager.timeEvent([_constants4.METRIC_EVENT_NAMES.CAMPAIGN_PREVIEW_REMOVE_SUCCESS, _constants4.METRIC_EVENT_NAMES.CAMPAIGN_PREVIEW_REMOVE_FAILED]);
|
|
1622
|
+
const result = await this.services.dialer.removePreviewContact({
|
|
1623
|
+
data: payload
|
|
1624
|
+
});
|
|
1625
|
+
this.metricsManager.trackEvent(_constants4.METRIC_EVENT_NAMES.CAMPAIGN_PREVIEW_REMOVE_SUCCESS, {
|
|
1626
|
+
..._MetricsManager.default.getCommonTrackingFieldForAQMResponse(result),
|
|
1627
|
+
interactionId: payload.interactionId,
|
|
1628
|
+
campaignId: payload.campaignId
|
|
1629
|
+
}, ['behavioral', 'business', 'operational']);
|
|
1630
|
+
_loggerProxy.default.log('Campaign preview contact removed successfully', {
|
|
1631
|
+
module: _constants.CC_FILE,
|
|
1632
|
+
method: _constants.METHODS.REMOVE_PREVIEW_CONTACT,
|
|
1633
|
+
trackingId: result.trackingId,
|
|
1634
|
+
interactionId: payload.interactionId
|
|
1635
|
+
});
|
|
1636
|
+
return result;
|
|
1637
|
+
} catch (error) {
|
|
1638
|
+
const failure = error.details;
|
|
1639
|
+
this.metricsManager.trackEvent(_constants4.METRIC_EVENT_NAMES.CAMPAIGN_PREVIEW_REMOVE_FAILED, {
|
|
1640
|
+
..._MetricsManager.default.getCommonTrackingFieldForAQMResponseFailed(failure),
|
|
1641
|
+
interactionId: payload.interactionId,
|
|
1642
|
+
campaignId: payload.campaignId
|
|
1643
|
+
}, ['behavioral', 'business', 'operational']);
|
|
1644
|
+
const {
|
|
1645
|
+
error: detailedError
|
|
1646
|
+
} = (0, _Utils.getErrorDetails)(error, _constants.METHODS.REMOVE_PREVIEW_CONTACT, _constants.CC_FILE);
|
|
1647
|
+
throw detailedError;
|
|
1648
|
+
}
|
|
1649
|
+
}
|
|
1650
|
+
|
|
1437
1651
|
/**
|
|
1438
1652
|
* Fetches outdial ANI (Automatic Number Identification) entries for an outdial ANI ID.
|
|
1439
1653
|
*
|