@webex/contact-center 3.11.0 → 3.12.0-auth-prejoin-fetch.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/.sdd/manifest.json +883 -0
- package/AGENTS.md +94 -0
- package/ai-docs/ARCHITECTURE.md +168 -0
- package/ai-docs/CONTRACTS.md +50 -0
- package/ai-docs/GETTING_STARTED.md +168 -0
- package/ai-docs/GLOSSARY.md +43 -0
- package/ai-docs/README.md +138 -0
- package/ai-docs/REVIEW_CHECKLIST.md +41 -0
- package/ai-docs/RULES.md +444 -0
- package/ai-docs/SECURITY.md +52 -0
- package/ai-docs/SERVICE_STATE.md +48 -0
- package/ai-docs/SPEC_INDEX.md +65 -0
- package/ai-docs/adr/0001-spec-source-policy.md +55 -0
- package/ai-docs/adr/README.md +8 -0
- package/ai-docs/adr/_adr-template.md +31 -0
- package/ai-docs/contact-center-spec.md +359 -0
- package/ai-docs/features/consult-transfer-list-policy/spec/feature-spec.md +362 -0
- package/ai-docs/features/generated-spec-conformance-fidelity-remediation/spec/feature-spec.md +117 -0
- package/ai-docs/features/residual-warning-coverage-completion/spec/feature-spec.md +203 -0
- package/ai-docs/features/validator-code-fidelity-drift-fix/spec/feature-spec.md +315 -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 +818 -59
- package/dist/cc.js.map +1 -1
- package/dist/config.js +13 -0
- package/dist/config.js.map +1 -1
- package/dist/constants.js +31 -3
- package/dist/constants.js.map +1 -1
- package/dist/index.js +27 -5
- package/dist/index.js.map +1 -1
- package/dist/metrics/behavioral-events.js +127 -0
- package/dist/metrics/behavioral-events.js.map +1 -1
- package/dist/metrics/constants.js +34 -3
- package/dist/metrics/constants.js.map +1 -1
- package/dist/services/AddressBook.js +18 -15
- package/dist/services/AddressBook.js.map +1 -1
- package/dist/services/AnswerCallOnWebexService.js +174 -0
- package/dist/services/AnswerCallOnWebexService.js.map +1 -0
- package/dist/services/ApiAiAssistant.js +318 -0
- package/dist/services/ApiAiAssistant.js.map +1 -0
- package/dist/services/EntryPoint.js +46 -68
- package/dist/services/EntryPoint.js.map +1 -1
- package/dist/services/Queue.js +27 -22
- package/dist/services/Queue.js.map +1 -1
- package/dist/services/UserPreference.js +427 -0
- package/dist/services/UserPreference.js.map +1 -0
- package/dist/services/WebexCrossClientService.js +171 -0
- package/dist/services/WebexCrossClientService.js.map +1 -0
- package/dist/services/WxAppTelephonyMercurySync.js +93 -0
- package/dist/services/WxAppTelephonyMercurySync.js.map +1 -0
- package/dist/services/agent/types.js.map +1 -1
- package/dist/services/config/Util.js +11 -4
- package/dist/services/config/Util.js.map +1 -1
- package/dist/services/config/constants.js +45 -8
- package/dist/services/config/constants.js.map +1 -1
- package/dist/services/config/index.js +41 -2
- package/dist/services/config/index.js.map +1 -1
- package/dist/services/config/types.js +70 -8
- package/dist/services/config/types.js.map +1 -1
- package/dist/services/constants.js +27 -1
- package/dist/services/constants.js.map +1 -1
- package/dist/services/core/Err.js.map +1 -1
- package/dist/services/core/Utils.js +122 -25
- package/dist/services/core/Utils.js.map +1 -1
- package/dist/services/core/WebexRequest.js +6 -2
- package/dist/services/core/WebexRequest.js.map +1 -1
- package/dist/services/core/aqm-reqs.js +119 -30
- package/dist/services/core/aqm-reqs.js.map +1 -1
- package/dist/services/core/types.js.map +1 -1
- package/dist/services/core/websocket/WebSocketManager.js +22 -6
- package/dist/services/core/websocket/WebSocketManager.js.map +1 -1
- package/dist/services/core/websocket/connection-service.js +3 -1
- package/dist/services/core/websocket/connection-service.js.map +1 -1
- package/dist/services/core/websocket/types.js.map +1 -1
- package/dist/services/index.js +6 -0
- package/dist/services/index.js.map +1 -1
- package/dist/services/task/Task.js +754 -0
- package/dist/services/task/Task.js.map +1 -0
- package/dist/services/task/TaskFactory.js +49 -0
- package/dist/services/task/TaskFactory.js.map +1 -0
- package/dist/services/task/TaskManager.js +1073 -447
- package/dist/services/task/TaskManager.js.map +1 -1
- package/dist/services/task/TaskUtils.js +220 -23
- package/dist/services/task/TaskUtils.js.map +1 -1
- package/dist/services/task/WebexCallingUtils.js +70 -0
- package/dist/services/task/WebexCallingUtils.js.map +1 -0
- package/dist/services/task/constants.js +26 -2
- package/dist/services/task/constants.js.map +1 -1
- package/dist/services/task/contact.js +29 -0
- package/dist/services/task/contact.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/digital/Digital.js +78 -0
- package/dist/services/task/digital/Digital.js.map +1 -0
- package/dist/services/task/state-machine/TaskStateMachine.js +971 -0
- package/dist/services/task/state-machine/TaskStateMachine.js.map +1 -0
- package/dist/services/task/state-machine/actions.js +572 -0
- package/dist/services/task/state-machine/actions.js.map +1 -0
- package/dist/services/task/state-machine/constants.js +161 -0
- package/dist/services/task/state-machine/constants.js.map +1 -0
- package/dist/services/task/state-machine/guards.js +409 -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 +703 -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 +243 -5
- package/dist/services/task/types.js.map +1 -1
- package/dist/services/task/voice/Voice.js +1380 -0
- package/dist/services/task/voice/Voice.js.map +1 -0
- package/dist/services/task/voice/WebRTC.js +152 -0
- package/dist/services/task/voice/WebRTC.js.map +1 -0
- package/dist/services/task/voice/wxAppVoiceMethods.js +201 -0
- package/dist/services/task/voice/wxAppVoiceMethods.js.map +1 -0
- package/dist/services/wxAppTelephonyUtils.js +19 -0
- package/dist/services/wxAppTelephonyUtils.js.map +1 -0
- package/dist/types/cc.d.ts +967 -0
- package/dist/types/config.d.ts +79 -0
- package/dist/types/constants.d.ts +74 -0
- package/dist/types/index.d.ts +201 -0
- package/dist/types/logger-proxy.d.ts +71 -0
- package/dist/types/metrics/MetricsManager.d.ts +223 -0
- package/dist/types/metrics/behavioral-events.d.ts +29 -0
- package/dist/types/metrics/constants.d.ts +183 -0
- package/dist/types/services/AddressBook.d.ts +75 -0
- package/dist/types/services/AnswerCallOnWebexService.d.ts +37 -0
- package/dist/types/services/ApiAiAssistant.d.ts +49 -0
- package/dist/types/services/EntryPoint.d.ts +69 -0
- package/dist/types/services/Queue.d.ts +78 -0
- package/dist/types/services/UserPreference.d.ts +118 -0
- package/dist/types/services/WebCallingService.d.ts +1 -0
- package/dist/types/services/WebexCrossClientService.d.ts +28 -0
- package/dist/types/services/WxAppTelephonyMercurySync.d.ts +28 -0
- package/dist/types/services/agent/index.d.ts +46 -0
- package/dist/types/services/agent/types.d.ts +413 -0
- package/dist/types/services/config/Util.d.ts +20 -0
- package/dist/types/services/config/constants.d.ts +273 -0
- package/dist/types/services/config/index.d.ts +177 -0
- package/dist/types/services/config/types.d.ts +1381 -0
- package/dist/types/services/constants.d.ts +110 -0
- package/dist/types/services/core/Err.d.ts +127 -0
- package/dist/types/services/core/GlobalTypes.d.ts +58 -0
- package/dist/types/services/core/Utils.d.ts +121 -0
- package/dist/types/services/core/WebexRequest.d.ts +23 -0
- package/dist/types/services/core/aqm-reqs.d.ts +65 -0
- package/dist/types/services/core/constants.d.ts +99 -0
- package/dist/types/services/core/types.d.ts +49 -0
- package/dist/types/services/core/websocket/WebSocketManager.d.ts +36 -0
- package/dist/types/services/core/websocket/connection-service.d.ts +27 -0
- package/dist/types/services/core/websocket/keepalive.worker.d.ts +2 -0
- package/dist/types/services/core/websocket/types.d.ts +37 -0
- package/dist/types/services/index.d.ts +54 -0
- package/dist/types/services/task/AutoWrapup.d.ts +40 -0
- package/dist/types/services/task/Task.d.ts +175 -0
- package/dist/types/services/task/TaskFactory.d.ts +13 -0
- package/dist/types/services/task/TaskManager.d.ts +1 -0
- package/dist/types/services/task/TaskUtils.d.ts +138 -0
- package/dist/types/services/task/WebexCallingUtils.d.ts +11 -0
- package/dist/types/services/task/constants.d.ts +94 -0
- package/dist/types/services/task/contact.d.ts +73 -0
- package/dist/types/services/task/dialer.d.ts +73 -0
- package/dist/types/services/task/digital/Digital.d.ts +22 -0
- package/dist/types/services/task/state-machine/TaskStateMachine.d.ts +1398 -0
- package/dist/types/services/task/state-machine/actions.d.ts +10 -0
- package/dist/types/services/task/state-machine/constants.d.ts +107 -0
- package/dist/types/services/task/state-machine/guards.d.ts +103 -0
- package/dist/types/services/task/state-machine/index.d.ts +13 -0
- package/dist/types/services/task/state-machine/types.d.ts +277 -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 +1933 -0
- package/dist/types/services/task/voice/Voice.d.ts +223 -0
- package/dist/types/services/task/voice/WebRTC.d.ts +53 -0
- package/dist/types/services/task/voice/wxAppVoiceMethods.d.ts +52 -0
- package/dist/types/services/wxAppTelephonyUtils.d.ts +5 -0
- package/dist/types/types.d.ts +784 -0
- package/dist/types/utils/PageCache.d.ts +190 -0
- package/dist/types/webex-config.d.ts +53 -0
- package/dist/types/webex.d.ts +8 -0
- package/dist/types.js +137 -3
- package/dist/types.js.map +1 -1
- package/dist/utils/PageCache.js +19 -5
- package/dist/utils/PageCache.js.map +1 -1
- package/dist/webex.js +14 -2
- package/dist/webex.js.map +1 -1
- package/package.json +16 -12
- package/src/cc.ts +983 -60
- package/src/config.ts +13 -0
- package/src/constants.ts +29 -1
- package/src/index.ts +26 -5
- package/src/metrics/ai-docs/AGENTS.md +350 -0
- package/src/metrics/ai-docs/ARCHITECTURE.md +338 -0
- package/src/metrics/ai-docs/metrics-spec.md +860 -0
- package/src/metrics/behavioral-events.ts +134 -0
- package/src/metrics/constants.ts +39 -3
- package/src/services/AddressBook.ts +17 -6
- package/src/services/AnswerCallOnWebexService.ts +206 -0
- package/src/services/ApiAiAssistant.ts +412 -0
- package/src/services/EntryPoint.ts +59 -60
- package/src/services/Queue.ts +29 -12
- package/src/services/UserPreference.ts +509 -0
- package/src/services/WebexCrossClientService.ts +212 -0
- package/src/services/WxAppTelephonyMercurySync.ts +115 -0
- package/src/services/agent/ai-docs/AGENTS.md +240 -0
- package/src/services/agent/ai-docs/ARCHITECTURE.md +304 -0
- package/src/services/agent/ai-docs/agent-spec.md +504 -0
- package/src/services/agent/types.ts +1 -1
- package/src/services/ai-docs/AGENTS.md +386 -0
- package/src/services/ai-docs/services-spec.md +497 -0
- package/src/services/config/Util.ts +13 -2
- package/src/services/config/ai-docs/AGENTS.md +255 -0
- package/src/services/config/ai-docs/ARCHITECTURE.md +426 -0
- package/src/services/config/ai-docs/config-spec.md +675 -0
- package/src/services/config/constants.ts +47 -7
- package/src/services/config/index.ts +45 -1
- package/src/services/config/types.ts +253 -11
- package/src/services/constants.ts +29 -0
- package/src/services/core/Err.ts +4 -0
- package/src/services/core/Utils.ts +143 -30
- package/src/services/core/WebexRequest.ts +3 -1
- package/src/services/core/ai-docs/AGENTS.md +381 -0
- package/src/services/core/ai-docs/ARCHITECTURE.md +698 -0
- package/src/services/core/ai-docs/core-spec.md +787 -0
- package/src/services/core/aqm-reqs.ts +125 -32
- package/src/services/core/types.ts +2 -0
- package/src/services/core/websocket/WebSocketManager.ts +23 -6
- package/src/services/core/websocket/connection-service.ts +5 -1
- package/src/services/core/websocket/types.ts +1 -1
- package/src/services/index.ts +4 -0
- package/src/services/task/Task.ts +908 -0
- package/src/services/task/TaskFactory.ts +60 -0
- package/src/services/task/TaskManager.ts +1291 -513
- package/src/services/task/TaskUtils.ts +314 -24
- package/src/services/task/WebexCallingUtils.ts +136 -0
- package/src/services/task/ai-docs/AGENTS.md +457 -0
- package/src/services/task/ai-docs/ARCHITECTURE.md +595 -0
- package/src/services/task/ai-docs/task-spec.md +1469 -0
- package/src/services/task/constants.ts +26 -0
- package/src/services/task/contact.ts +30 -0
- package/src/services/task/dialer.ts +136 -1
- package/src/services/task/digital/Digital.ts +97 -0
- package/src/services/task/state-machine/TaskStateMachine.ts +1313 -0
- package/src/services/task/state-machine/actions.ts +741 -0
- package/src/services/task/state-machine/ai-docs/AGENTS.md +462 -0
- package/src/services/task/state-machine/ai-docs/ARCHITECTURE.md +1146 -0
- package/src/services/task/state-machine/ai-docs/task-state-machine-spec.md +2209 -0
- package/src/services/task/state-machine/constants.ts +172 -0
- package/src/services/task/state-machine/guards.ts +498 -0
- package/src/services/task/state-machine/index.ts +28 -0
- package/src/services/task/state-machine/types.ts +258 -0
- package/src/services/task/state-machine/uiControlsComputer.ts +1135 -0
- package/src/services/task/taskDataNormalizer.ts +137 -0
- package/src/services/task/types.ts +843 -70
- package/src/services/task/voice/Voice.ts +1720 -0
- package/src/services/task/voice/WebRTC.ts +191 -0
- package/src/services/task/voice/wxAppVoiceMethods.ts +307 -0
- package/src/services/wxAppTelephonyUtils.ts +14 -0
- package/src/types.ts +238 -11
- package/src/utils/AGENTS.md +289 -0
- package/src/utils/PageCache.ts +38 -5
- package/src/utils/ai-docs/utils-spec.md +391 -0
- package/src/webex.js +2 -0
- package/test/unit/spec/cc.ts +1856 -122
- package/test/unit/spec/logger-proxy.ts +70 -0
- package/test/unit/spec/metrics/behavioral-events.ts +18 -0
- package/test/unit/spec/services/AddressBook.ts +37 -6
- package/test/unit/spec/services/AnswerCallOnWebexService.ts +223 -0
- package/test/unit/spec/services/ApiAiAssistant.ts +273 -0
- package/test/unit/spec/services/EntryPoint.ts +87 -40
- package/test/unit/spec/services/Queue.ts +123 -12
- package/test/unit/spec/services/UserPreference.ts +401 -0
- package/test/unit/spec/services/WebCallingService.ts +7 -1
- package/test/unit/spec/services/WebexCrossClientService.ts +261 -0
- package/test/unit/spec/services/WxAppTelephonyMercurySync.ts +113 -0
- package/test/unit/spec/services/config/Util.ts +85 -0
- package/test/unit/spec/services/config/index.ts +85 -29
- package/test/unit/spec/services/core/Utils.ts +481 -2
- package/test/unit/spec/services/core/WebexRequest.ts +3 -1
- package/test/unit/spec/services/core/aqm-reqs.ts +113 -1
- package/test/unit/spec/services/core/websocket/WebSocketManager.ts +137 -41
- package/test/unit/spec/services/core/websocket/connection-service.ts +3 -1
- package/test/unit/spec/services/task/AutoWrapup.ts +63 -0
- package/test/unit/spec/services/task/Task.ts +677 -0
- package/test/unit/spec/services/task/TaskFactory.ts +99 -0
- package/test/unit/spec/services/task/TaskManager.ts +2209 -918
- package/test/unit/spec/services/task/TaskUtils.ts +235 -0
- package/test/unit/spec/services/task/WebexCallingUtils.ts +153 -0
- package/test/unit/spec/services/task/contact.ts +33 -0
- package/test/unit/spec/services/task/dialer.ts +372 -96
- package/test/unit/spec/services/task/digital/Digital.ts +105 -0
- package/test/unit/spec/services/task/state-machine/TaskStateMachine.ts +3433 -0
- package/test/unit/spec/services/task/state-machine/guards.ts +839 -0
- package/test/unit/spec/services/task/state-machine/types.ts +18 -0
- package/test/unit/spec/services/task/state-machine/uiControlsComputer.ts +3101 -0
- package/test/unit/spec/services/task/taskTestUtils.ts +87 -0
- package/test/unit/spec/services/task/voice/Voice.ts +1523 -0
- package/test/unit/spec/services/task/voice/WebRTC.ts +235 -0
- package/test/unit/spec/services/task/voice/wxAppVoiceMethods.ts +459 -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/src/services/task/index.ts +0 -1801
- package/test/unit/spec/services/task/index.ts +0 -2184
package/src/cc.ts
CHANGED
|
@@ -25,6 +25,7 @@ import {
|
|
|
25
25
|
UploadLogsResponse,
|
|
26
26
|
UpdateDeviceTypeResponse,
|
|
27
27
|
GenericError,
|
|
28
|
+
ConfigFlags,
|
|
28
29
|
} from './types';
|
|
29
30
|
import {
|
|
30
31
|
READY,
|
|
@@ -39,7 +40,7 @@ import {
|
|
|
39
40
|
METHODS,
|
|
40
41
|
} from './constants';
|
|
41
42
|
import {AGENT_STATE_AVAILABLE, AGENT_STATE_AVAILABLE_ID} from './services/config/constants';
|
|
42
|
-
import {AGENT, WEB_RTC_PREFIX} from './services/constants';
|
|
43
|
+
import {AGENT, RTD_SUBSCRIBE_API, SUBSCRIBE_API, WEB_RTC_PREFIX} from './services/constants';
|
|
43
44
|
import Services from './services';
|
|
44
45
|
import WebexRequest from './services/core/WebexRequest';
|
|
45
46
|
import LoggerProxy from './logger-proxy';
|
|
@@ -55,13 +56,24 @@ import {
|
|
|
55
56
|
import {ConnectionLostDetails} from './services/core/websocket/types';
|
|
56
57
|
import TaskManager from './services/task/TaskManager';
|
|
57
58
|
import WebCallingService from './services/WebCallingService';
|
|
58
|
-
import
|
|
59
|
+
import AnswerCallOnWebexService from './services/AnswerCallOnWebexService';
|
|
60
|
+
import WebexCrossClientService from './services/WebexCrossClientService';
|
|
61
|
+
import WxAppTelephonyMercurySync from './services/WxAppTelephonyMercurySync';
|
|
62
|
+
import {
|
|
63
|
+
ITask,
|
|
64
|
+
TASK_EVENTS,
|
|
65
|
+
TaskResponse,
|
|
66
|
+
DialerPayload,
|
|
67
|
+
PreviewContactPayload,
|
|
68
|
+
} from './services/task/types';
|
|
59
69
|
import MetricsManager from './metrics/MetricsManager';
|
|
60
70
|
import {METRIC_EVENT_NAMES} from './metrics/constants';
|
|
61
71
|
import {Failure} from './services/core/GlobalTypes';
|
|
62
|
-
import EntryPoint from './services/EntryPoint';
|
|
63
|
-
import AddressBook from './services/AddressBook';
|
|
64
|
-
import Queue from './services/Queue';
|
|
72
|
+
import {EntryPoint} from './services/EntryPoint';
|
|
73
|
+
import {AddressBook} from './services/AddressBook';
|
|
74
|
+
import {Queue} from './services/Queue';
|
|
75
|
+
import {ApiAIAssistant} from './services/ApiAiAssistant';
|
|
76
|
+
import {UserPreference} from './services/UserPreference';
|
|
65
77
|
import type {
|
|
66
78
|
EntryPointListResponse,
|
|
67
79
|
EntryPointSearchParams,
|
|
@@ -119,6 +131,7 @@ import type {
|
|
|
119
131
|
* - `task:established` - Task/call has been connected
|
|
120
132
|
* - `task:ended` - Task/call has ended
|
|
121
133
|
* - `task:error` - An error occurred during task handling
|
|
134
|
+
* - `task:campaignPreviewReservation` - Campaign preview contact offered to agent
|
|
122
135
|
*
|
|
123
136
|
* @public
|
|
124
137
|
*
|
|
@@ -222,6 +235,34 @@ export default class ContactCenter extends WebexPlugin implements IContactCenter
|
|
|
222
235
|
*/
|
|
223
236
|
private webCallingService: WebCallingService;
|
|
224
237
|
|
|
238
|
+
/**
|
|
239
|
+
* REST telephony for wxApp thick-client answer (WXCC-6026)
|
|
240
|
+
* @private
|
|
241
|
+
*/
|
|
242
|
+
private answerCallOnWebexService: AnswerCallOnWebexService;
|
|
243
|
+
|
|
244
|
+
/**
|
|
245
|
+
* usersub cross-client state for Webex App toast suppression
|
|
246
|
+
* @private
|
|
247
|
+
*/
|
|
248
|
+
private webexCrossClientService: WebexCrossClientService;
|
|
249
|
+
|
|
250
|
+
/**
|
|
251
|
+
* Mercury telephony mute sync for wxApp thick-client answer
|
|
252
|
+
* @private
|
|
253
|
+
*/
|
|
254
|
+
private wxAppTelephonyMercurySync: WxAppTelephonyMercurySync;
|
|
255
|
+
|
|
256
|
+
/** True when wxApp mute sync opened Mercury (Extension/DN-only profiles). */
|
|
257
|
+
private wxAppMercuryConnectedByCc = false;
|
|
258
|
+
|
|
259
|
+
/** True when wxApp mute sync registered the Webex device. */
|
|
260
|
+
private wxAppDeviceRegisteredByCc = false;
|
|
261
|
+
|
|
262
|
+
private static readonly WXAPP_FALSE_PUBLISH_RETRY_DELAY_MS = 30_000;
|
|
263
|
+
private static readonly WXAPP_FALSE_PUBLISH_MAX_RETRIES = 3;
|
|
264
|
+
private wxAppFalsePublishRetryTimer?: ReturnType<typeof setTimeout>;
|
|
265
|
+
|
|
225
266
|
/**
|
|
226
267
|
* Core service managers for Contact Center operations
|
|
227
268
|
* Includes agent, connection, and configuration services
|
|
@@ -317,7 +358,45 @@ export default class ContactCenter extends WebexPlugin implements IContactCenter
|
|
|
317
358
|
* });
|
|
318
359
|
* ```
|
|
319
360
|
*/
|
|
320
|
-
|
|
361
|
+
public queue: Queue;
|
|
362
|
+
|
|
363
|
+
/**
|
|
364
|
+
* API instance for managing Webex Contact Center user preferences
|
|
365
|
+
* Provides functionality to get, create, update, and delete user preferences
|
|
366
|
+
* @type {UserPreference}
|
|
367
|
+
* @public
|
|
368
|
+
* @example
|
|
369
|
+
* ```typescript
|
|
370
|
+
* const cc = webex.cc;
|
|
371
|
+
* await cc.register();
|
|
372
|
+
* await cc.stationLogin({ teamId: 'team123', loginOption: 'BROWSER' });
|
|
373
|
+
*
|
|
374
|
+
* // Get user preferences for current user
|
|
375
|
+
* const preferences = await cc.userPreference.getUserPreference();
|
|
376
|
+
*
|
|
377
|
+
* // Create new user preferences
|
|
378
|
+
* const newPrefs = await cc.userPreference.createUserPreference({
|
|
379
|
+
* userId: 'user123',
|
|
380
|
+
* preferences: { e911Reminder: true }
|
|
381
|
+
* });
|
|
382
|
+
*
|
|
383
|
+
* // Update user preferences
|
|
384
|
+
* const updatedPrefs = await cc.userPreference.updateUserPreference('user123', {
|
|
385
|
+
* preferences: { e911Reminder: false }
|
|
386
|
+
* });
|
|
387
|
+
*
|
|
388
|
+
* // Delete user preferences
|
|
389
|
+
* await cc.userPreference.deleteUserPreference('user123');
|
|
390
|
+
* ```
|
|
391
|
+
*/
|
|
392
|
+
public userPreference: UserPreference;
|
|
393
|
+
|
|
394
|
+
/**
|
|
395
|
+
* API instance for AI Assistant operations such as transcript controls.
|
|
396
|
+
* @type {ApiAIAssistant}
|
|
397
|
+
* @public
|
|
398
|
+
*/
|
|
399
|
+
public apiAIAssistant: ApiAIAssistant;
|
|
321
400
|
|
|
322
401
|
/**
|
|
323
402
|
* Logger utility for Contact Center plugin
|
|
@@ -342,6 +421,7 @@ export default class ContactCenter extends WebexPlugin implements IContactCenter
|
|
|
342
421
|
this.$webex.once(READY, () => {
|
|
343
422
|
// @ts-ignore
|
|
344
423
|
this.$config = this.config;
|
|
424
|
+
this.validatePluginConfig();
|
|
345
425
|
|
|
346
426
|
/**
|
|
347
427
|
* This is used for handling the async requests by sending webex.request and wait for corresponding websocket event.
|
|
@@ -354,15 +434,21 @@ export default class ContactCenter extends WebexPlugin implements IContactCenter
|
|
|
354
434
|
webex: this.$webex,
|
|
355
435
|
connectionConfig: this.getConnectionConfig(),
|
|
356
436
|
});
|
|
357
|
-
this.services.webSocketManager.on('message', this.handleWebsocketMessage);
|
|
358
437
|
|
|
359
438
|
this.webCallingService = new WebCallingService(this.$webex);
|
|
439
|
+
this.answerCallOnWebexService = new AnswerCallOnWebexService(this.$webex);
|
|
440
|
+
this.webexCrossClientService = new WebexCrossClientService(this.$webex);
|
|
441
|
+
this.wxAppTelephonyMercurySync = new WxAppTelephonyMercurySync(this.$webex);
|
|
442
|
+
this.apiAIAssistant = new ApiAIAssistant(this.$webex);
|
|
360
443
|
this.metricsManager = MetricsManager.getInstance({webex: this.$webex});
|
|
361
444
|
this.taskManager = TaskManager.getTaskManager(
|
|
445
|
+
this.apiAIAssistant,
|
|
362
446
|
this.services.contact,
|
|
363
447
|
this.webCallingService,
|
|
364
|
-
this.services.webSocketManager
|
|
448
|
+
this.services.webSocketManager,
|
|
449
|
+
this.services.rtdWebSocketManager
|
|
365
450
|
);
|
|
451
|
+
this.taskManager.setAnswerCallOnWebexService(this.answerCallOnWebexService);
|
|
366
452
|
this.incomingTaskListener();
|
|
367
453
|
|
|
368
454
|
// Initialize API instances
|
|
@@ -370,8 +456,7 @@ export default class ContactCenter extends WebexPlugin implements IContactCenter
|
|
|
370
456
|
this.entryPoint = new EntryPoint(this.$webex);
|
|
371
457
|
this.addressBook = new AddressBook(this.$webex, () => this.agentConfig?.addressBookId);
|
|
372
458
|
this.queue = new Queue(this.$webex);
|
|
373
|
-
|
|
374
|
-
// Initialize logger
|
|
459
|
+
this.userPreference = new UserPreference(this.$webex, () => this.agentConfig?.agentId);
|
|
375
460
|
LoggerProxy.initialize(this.$webex.logger);
|
|
376
461
|
});
|
|
377
462
|
}
|
|
@@ -396,6 +481,16 @@ export default class ContactCenter extends WebexPlugin implements IContactCenter
|
|
|
396
481
|
this.trigger(TASK_EVENTS.TASK_HYDRATE, task);
|
|
397
482
|
};
|
|
398
483
|
|
|
484
|
+
/**
|
|
485
|
+
* Handles multi-login hydrate events for SDK instances without Mobius registration
|
|
486
|
+
* @private
|
|
487
|
+
* @param {ITask} task The task object associated with the multi-login hydrate
|
|
488
|
+
*/
|
|
489
|
+
private handleTaskMultiLoginHydrate = (task: ITask) => {
|
|
490
|
+
// @ts-ignore
|
|
491
|
+
this.trigger(TASK_EVENTS.TASK_MULTI_LOGIN_HYDRATE, task);
|
|
492
|
+
};
|
|
493
|
+
|
|
399
494
|
/**
|
|
400
495
|
* Handles task merged events when tasks are combined eg: EPDN merge/transfer
|
|
401
496
|
* @private
|
|
@@ -406,6 +501,20 @@ export default class ContactCenter extends WebexPlugin implements IContactCenter
|
|
|
406
501
|
this.trigger(TASK_EVENTS.TASK_MERGED, task);
|
|
407
502
|
};
|
|
408
503
|
|
|
504
|
+
/**
|
|
505
|
+
* Handles campaign preview reservation events when a contact is offered to the agent
|
|
506
|
+
* @private
|
|
507
|
+
* @param {ITask} task The campaign reservation task
|
|
508
|
+
*/
|
|
509
|
+
private handleCampaignPreviewReservation = (task: ITask) => {
|
|
510
|
+
// @ts-ignore
|
|
511
|
+
this.trigger(TASK_EVENTS.TASK_CAMPAIGN_PREVIEW_RESERVATION, task);
|
|
512
|
+
};
|
|
513
|
+
|
|
514
|
+
private handleRTDWebsocketMessage = (event: string) => {
|
|
515
|
+
this.taskManager.handleRealtimeWebsocketEvent(event);
|
|
516
|
+
};
|
|
517
|
+
|
|
409
518
|
/**
|
|
410
519
|
* Sets up event listeners for incoming tasks and task hydration
|
|
411
520
|
* Subscribes to task events from the task manager
|
|
@@ -414,7 +523,12 @@ export default class ContactCenter extends WebexPlugin implements IContactCenter
|
|
|
414
523
|
private incomingTaskListener() {
|
|
415
524
|
this.taskManager.on(TASK_EVENTS.TASK_INCOMING, this.handleIncomingTask);
|
|
416
525
|
this.taskManager.on(TASK_EVENTS.TASK_HYDRATE, this.handleTaskHydrate);
|
|
526
|
+
this.taskManager.on(TASK_EVENTS.TASK_MULTI_LOGIN_HYDRATE, this.handleTaskMultiLoginHydrate);
|
|
417
527
|
this.taskManager.on(TASK_EVENTS.TASK_MERGED, this.handleTaskMerged);
|
|
528
|
+
this.taskManager.on(
|
|
529
|
+
TASK_EVENTS.TASK_CAMPAIGN_PREVIEW_RESERVATION,
|
|
530
|
+
this.handleCampaignPreviewReservation
|
|
531
|
+
);
|
|
418
532
|
}
|
|
419
533
|
|
|
420
534
|
/**
|
|
@@ -454,7 +568,7 @@ export default class ContactCenter extends WebexPlugin implements IContactCenter
|
|
|
454
568
|
* ```
|
|
455
569
|
*/
|
|
456
570
|
public async register(): Promise<Profile> {
|
|
457
|
-
LoggerProxy.
|
|
571
|
+
LoggerProxy.log('Starting CC SDK registration', {
|
|
458
572
|
module: CC_FILE,
|
|
459
573
|
method: METHODS.REGISTER,
|
|
460
574
|
});
|
|
@@ -464,6 +578,7 @@ export default class ContactCenter extends WebexPlugin implements IContactCenter
|
|
|
464
578
|
METRIC_EVENT_NAMES.WEBSOCKET_REGISTER_FAILED,
|
|
465
579
|
]);
|
|
466
580
|
this.setupEventListeners();
|
|
581
|
+
this.services.webSocketManager.on('message', this.handleWebsocketMessage);
|
|
467
582
|
|
|
468
583
|
const resp = await this.connectWebsocket();
|
|
469
584
|
// Ensure 'dn' is always populated from 'defaultDn'
|
|
@@ -543,11 +658,21 @@ export default class ContactCenter extends WebexPlugin implements IContactCenter
|
|
|
543
658
|
|
|
544
659
|
this.taskManager.off(TASK_EVENTS.TASK_INCOMING, this.handleIncomingTask);
|
|
545
660
|
this.taskManager.off(TASK_EVENTS.TASK_HYDRATE, this.handleTaskHydrate);
|
|
661
|
+
this.taskManager.off(TASK_EVENTS.TASK_MULTI_LOGIN_HYDRATE, this.handleTaskMultiLoginHydrate);
|
|
662
|
+
this.taskManager.off(
|
|
663
|
+
TASK_EVENTS.TASK_CAMPAIGN_PREVIEW_RESERVATION,
|
|
664
|
+
this.handleCampaignPreviewReservation
|
|
665
|
+
);
|
|
546
666
|
this.taskManager.unregisterIncomingCallEvent();
|
|
547
667
|
|
|
548
668
|
this.services.webSocketManager.off('message', this.handleWebsocketMessage);
|
|
669
|
+
this.services.rtdWebSocketManager.off('message', this.handleRTDWebsocketMessage);
|
|
549
670
|
this.services.connectionService.off('connectionLost', this.handleConnectionLost);
|
|
550
671
|
|
|
672
|
+
const {publishError: wxAppPublishError} = await this.teardownWxAppLocalState({
|
|
673
|
+
clearInitFlag: true,
|
|
674
|
+
});
|
|
675
|
+
|
|
551
676
|
if (
|
|
552
677
|
this.agentConfig.webRtcEnabled &&
|
|
553
678
|
this.agentConfig.loginVoiceOptions.includes(LoginOption.BROWSER)
|
|
@@ -568,10 +693,21 @@ export default class ContactCenter extends WebexPlugin implements IContactCenter
|
|
|
568
693
|
if (!this.services.webSocketManager.isSocketClosed) {
|
|
569
694
|
this.services.webSocketManager.close(false, 'Unregistering the SDK');
|
|
570
695
|
}
|
|
696
|
+
if (this.services.rtdWebSocketManager && !this.services.rtdWebSocketManager.isSocketClosed) {
|
|
697
|
+
this.services.rtdWebSocketManager.close(false, 'Unregistering the SDK');
|
|
698
|
+
}
|
|
699
|
+
|
|
700
|
+
if (this.services.rtdWebSocketManager && !this.services.rtdWebSocketManager.isSocketClosed) {
|
|
701
|
+
this.services.rtdWebSocketManager.close(false, 'Unregistering the RTD websocket');
|
|
702
|
+
}
|
|
571
703
|
|
|
572
704
|
// Clear any cached agent configuration
|
|
573
705
|
this.agentConfig = null;
|
|
574
706
|
|
|
707
|
+
if (wxAppPublishError) {
|
|
708
|
+
throw wxAppPublishError;
|
|
709
|
+
}
|
|
710
|
+
|
|
575
711
|
LoggerProxy.log('Deregistered successfully', {
|
|
576
712
|
module: CC_FILE,
|
|
577
713
|
method: METHODS.DEREGISTER,
|
|
@@ -634,6 +770,9 @@ export default class ContactCenter extends WebexPlugin implements IContactCenter
|
|
|
634
770
|
* ```
|
|
635
771
|
*/
|
|
636
772
|
public async getBuddyAgents(data: BuddyAgents): Promise<BuddyAgentsResponse> {
|
|
773
|
+
const {action, state, mediaType = 'telephony'} = data;
|
|
774
|
+
const buddyAgentState = state ?? (action === 'Transfer' ? AGENT_STATE_AVAILABLE : undefined);
|
|
775
|
+
|
|
637
776
|
LoggerProxy.info('Fetching buddy agents', {
|
|
638
777
|
module: CC_FILE,
|
|
639
778
|
method: METHODS.GET_BUDDY_AGENTS,
|
|
@@ -644,15 +783,19 @@ export default class ContactCenter extends WebexPlugin implements IContactCenter
|
|
|
644
783
|
METRIC_EVENT_NAMES.FETCH_BUDDY_AGENTS_FAILED,
|
|
645
784
|
]);
|
|
646
785
|
const resp = await this.services.agent.buddyAgents({
|
|
647
|
-
data: {
|
|
786
|
+
data: {
|
|
787
|
+
agentProfileId: this.agentConfig.agentProfileID,
|
|
788
|
+
mediaType,
|
|
789
|
+
...(buddyAgentState ? {state: buddyAgentState} : {}),
|
|
790
|
+
},
|
|
648
791
|
});
|
|
649
792
|
|
|
650
793
|
this.metricsManager.trackEvent(
|
|
651
794
|
METRIC_EVENT_NAMES.FETCH_BUDDY_AGENTS_SUCCESS,
|
|
652
795
|
{
|
|
653
796
|
...MetricsManager.getCommonTrackingFieldForAQMResponse(resp),
|
|
654
|
-
mediaType
|
|
655
|
-
buddyAgentState
|
|
797
|
+
mediaType,
|
|
798
|
+
buddyAgentState,
|
|
656
799
|
buddyAgentCount: resp.data.agentList.length,
|
|
657
800
|
},
|
|
658
801
|
['operational']
|
|
@@ -672,8 +815,8 @@ export default class ContactCenter extends WebexPlugin implements IContactCenter
|
|
|
672
815
|
METRIC_EVENT_NAMES.FETCH_BUDDY_AGENTS_FAILED,
|
|
673
816
|
{
|
|
674
817
|
...MetricsManager.getCommonTrackingFieldForAQMResponseFailed(failureResp),
|
|
675
|
-
mediaType
|
|
676
|
-
buddyAgentState
|
|
818
|
+
mediaType,
|
|
819
|
+
buddyAgentState,
|
|
677
820
|
},
|
|
678
821
|
['operational']
|
|
679
822
|
);
|
|
@@ -689,7 +832,7 @@ export default class ContactCenter extends WebexPlugin implements IContactCenter
|
|
|
689
832
|
* @private
|
|
690
833
|
*/
|
|
691
834
|
private async connectWebsocket() {
|
|
692
|
-
LoggerProxy.
|
|
835
|
+
LoggerProxy.log('Connecting to websocket', {
|
|
693
836
|
module: CC_FILE,
|
|
694
837
|
method: METHODS.CONNECT_WEBSOCKET,
|
|
695
838
|
});
|
|
@@ -697,6 +840,7 @@ export default class ContactCenter extends WebexPlugin implements IContactCenter
|
|
|
697
840
|
try {
|
|
698
841
|
const data = (await this.services.webSocketManager.initWebSocket({
|
|
699
842
|
body: this.getConnectionConfig(),
|
|
843
|
+
resource: SUBSCRIBE_API,
|
|
700
844
|
})) as WelcomeEvent;
|
|
701
845
|
|
|
702
846
|
const agentId = data.agentId;
|
|
@@ -708,14 +852,64 @@ export default class ContactCenter extends WebexPlugin implements IContactCenter
|
|
|
708
852
|
method: METHODS.CONNECT_WEBSOCKET,
|
|
709
853
|
});
|
|
710
854
|
|
|
855
|
+
const configFlags: ConfigFlags = {
|
|
856
|
+
isEndTaskEnabled: this.agentConfig.isEndTaskEnabled,
|
|
857
|
+
isEndConsultEnabled: this.agentConfig.isEndConsultEnabled,
|
|
858
|
+
webRtcEnabled: this.agentConfig.webRtcEnabled,
|
|
859
|
+
autoWrapup: this.agentConfig.wrapUpData?.wrapUpProps?.autoWrapup ?? false,
|
|
860
|
+
aiFeature: this.agentConfig.aiFeature,
|
|
861
|
+
consultTransfer: {
|
|
862
|
+
allowConsultToQueue: this.agentConfig.allowConsultToQueue,
|
|
863
|
+
accessQueue: this.agentConfig.accessQueue,
|
|
864
|
+
accessEntryPoint: this.agentConfig.accessEntryPoint,
|
|
865
|
+
accessBuddyTeam: this.agentConfig.accessBuddyTeam,
|
|
866
|
+
},
|
|
867
|
+
enableWxBetterTogether: this.isWxBetterTogetherEnabled(),
|
|
868
|
+
};
|
|
869
|
+
this.taskManager.setConfigFlags(configFlags);
|
|
711
870
|
// TODO: Make profile a singleton to make it available throughout app/sdk so we dont need to inject info everywhere
|
|
712
871
|
this.taskManager.setWrapupData(this.agentConfig.wrapUpData);
|
|
713
872
|
this.taskManager.setAgentId(this.agentConfig.agentId);
|
|
714
873
|
this.taskManager.setWebRtcEnabled(this.agentConfig.webRtcEnabled);
|
|
874
|
+
this.apiAIAssistant.setAIFeatureFlags(this.agentConfig.aiFeature);
|
|
875
|
+
|
|
876
|
+
/**
|
|
877
|
+
* RTD websocket currently supports realtime transcripts and suggested responses.
|
|
878
|
+
* Extend this condition when additional AI RTD features are introduced.
|
|
879
|
+
*/
|
|
880
|
+
if (
|
|
881
|
+
this.agentConfig.aiFeature?.realtimeTranscripts?.enable ||
|
|
882
|
+
this.agentConfig.aiFeature?.suggestedResponses?.enable
|
|
883
|
+
) {
|
|
884
|
+
LoggerProxy.info('Connecting to RTD websocket', {
|
|
885
|
+
module: CC_FILE,
|
|
886
|
+
method: METHODS.CONNECT_WEBSOCKET,
|
|
887
|
+
});
|
|
888
|
+
|
|
889
|
+
this.services.rtdWebSocketManager
|
|
890
|
+
.initWebSocket({
|
|
891
|
+
body: this.getConnectionConfig(),
|
|
892
|
+
resource: RTD_SUBSCRIBE_API,
|
|
893
|
+
})
|
|
894
|
+
.then(() => {
|
|
895
|
+
LoggerProxy.log('RTD websocket connected successfully', {
|
|
896
|
+
module: CC_FILE,
|
|
897
|
+
method: METHODS.CONNECT_WEBSOCKET,
|
|
898
|
+
});
|
|
899
|
+
this.services.rtdWebSocketManager.on('message', this.handleRTDWebsocketMessage);
|
|
900
|
+
})
|
|
901
|
+
.catch((error) => {
|
|
902
|
+
LoggerProxy.error(`Error connecting to RTD websocket ${error}`, {
|
|
903
|
+
module: CC_FILE,
|
|
904
|
+
method: METHODS.CONNECT_WEBSOCKET,
|
|
905
|
+
});
|
|
906
|
+
});
|
|
907
|
+
}
|
|
715
908
|
|
|
716
909
|
if (
|
|
717
910
|
this.agentConfig.webRtcEnabled &&
|
|
718
|
-
this.agentConfig.loginVoiceOptions.includes(LoginOption.BROWSER)
|
|
911
|
+
this.agentConfig.loginVoiceOptions.includes(LoginOption.BROWSER) &&
|
|
912
|
+
!this.isWebRTCRegistrationDisabled()
|
|
719
913
|
) {
|
|
720
914
|
try {
|
|
721
915
|
await this.$webex.internal.mercury.connect();
|
|
@@ -729,10 +923,23 @@ export default class ContactCenter extends WebexPlugin implements IContactCenter
|
|
|
729
923
|
method: METHODS.CONNECT_WEBSOCKET,
|
|
730
924
|
});
|
|
731
925
|
}
|
|
926
|
+
} else if (this.isWebRTCRegistrationDisabled()) {
|
|
927
|
+
LoggerProxy.info(
|
|
928
|
+
'Skipping Mobius registration because disableWebRTCRegistration is enabled',
|
|
929
|
+
{
|
|
930
|
+
module: CC_FILE,
|
|
931
|
+
method: METHODS.CONNECT_WEBSOCKET,
|
|
932
|
+
}
|
|
933
|
+
);
|
|
732
934
|
}
|
|
733
935
|
|
|
734
936
|
if (this.$config && this.$config.allowAutomatedRelogin) {
|
|
735
937
|
await this.silentRelogin();
|
|
938
|
+
} else {
|
|
939
|
+
LoggerProxy.log('Skipping silent relogin: allowAutomatedRelogin is disabled', {
|
|
940
|
+
module: CC_FILE,
|
|
941
|
+
method: METHODS.CONNECT_WEBSOCKET,
|
|
942
|
+
});
|
|
736
943
|
}
|
|
737
944
|
|
|
738
945
|
return this.agentConfig;
|
|
@@ -775,22 +982,37 @@ export default class ContactCenter extends WebexPlugin implements IContactCenter
|
|
|
775
982
|
* ```
|
|
776
983
|
*/
|
|
777
984
|
public async stationLogin(data: AgentLogin): Promise<StationLoginResponse> {
|
|
778
|
-
|
|
779
|
-
|
|
780
|
-
method: METHODS.STATION_LOGIN,
|
|
781
|
-
});
|
|
985
|
+
const loggerContext = {module: CC_FILE, method: METHODS.STATION_LOGIN};
|
|
986
|
+
|
|
782
987
|
try {
|
|
988
|
+
LoggerProxy.log(
|
|
989
|
+
`Starting agent station login | loginOption: ${data?.loginOption} teamId: ${data?.teamId}`,
|
|
990
|
+
loggerContext
|
|
991
|
+
);
|
|
783
992
|
this.metricsManager.timeEvent([
|
|
784
993
|
METRIC_EVENT_NAMES.STATION_LOGIN_SUCCESS,
|
|
785
994
|
METRIC_EVENT_NAMES.STATION_LOGIN_FAILED,
|
|
786
995
|
]);
|
|
787
996
|
|
|
788
|
-
|
|
789
|
-
|
|
790
|
-
|
|
791
|
-
|
|
997
|
+
const dialPlanEntries = this.agentConfig?.dialPlan?.dialPlanEntity ?? [];
|
|
998
|
+
if (data.loginOption === LoginOption.AGENT_DN) {
|
|
999
|
+
LoggerProxy.log(
|
|
1000
|
+
`Validating dial number | dialPlanEnabled: ${!!this.agentConfig
|
|
1001
|
+
?.dialPlan} | dialPlanEntryCount: ${dialPlanEntries.length}`,
|
|
1002
|
+
loggerContext
|
|
1003
|
+
);
|
|
1004
|
+
|
|
1005
|
+
if (!isValidDialNumber(data.dialNumber, dialPlanEntries)) {
|
|
1006
|
+
LoggerProxy.log(
|
|
1007
|
+
`Dial number validation failed | dialNumber: ${data.dialNumber} | dialPlanEntryCount: ${dialPlanEntries.length}`,
|
|
1008
|
+
loggerContext
|
|
1009
|
+
);
|
|
1010
|
+
const error = new Error('INVALID_DIAL_NUMBER');
|
|
1011
|
+
// @ts-ignore - adding custom key to the error object
|
|
1012
|
+
error.details = {data: {reason: 'INVALID_DIAL_NUMBER'}} as Failure;
|
|
792
1013
|
|
|
793
|
-
|
|
1014
|
+
throw error;
|
|
1015
|
+
}
|
|
794
1016
|
}
|
|
795
1017
|
|
|
796
1018
|
const loginResponse = await this.services.agent.stationLogin({
|
|
@@ -809,8 +1031,24 @@ export default class ContactCenter extends WebexPlugin implements IContactCenter
|
|
|
809
1031
|
},
|
|
810
1032
|
});
|
|
811
1033
|
|
|
812
|
-
if (
|
|
1034
|
+
if (
|
|
1035
|
+
this.agentConfig.webRtcEnabled &&
|
|
1036
|
+
data.loginOption === LoginOption.BROWSER &&
|
|
1037
|
+
!this.isWebRTCRegistrationDisabled()
|
|
1038
|
+
) {
|
|
813
1039
|
await this.webCallingService.registerWebCallingLine();
|
|
1040
|
+
} else if (
|
|
1041
|
+
this.agentConfig.webRtcEnabled &&
|
|
1042
|
+
data.loginOption === LoginOption.BROWSER &&
|
|
1043
|
+
this.isWebRTCRegistrationDisabled()
|
|
1044
|
+
) {
|
|
1045
|
+
LoggerProxy.info(
|
|
1046
|
+
'Skipping web calling line registration because disableWebRTCRegistration is enabled',
|
|
1047
|
+
{
|
|
1048
|
+
module: CC_FILE,
|
|
1049
|
+
method: METHODS.STATION_LOGIN,
|
|
1050
|
+
}
|
|
1051
|
+
);
|
|
814
1052
|
}
|
|
815
1053
|
|
|
816
1054
|
const resp = await loginResponse;
|
|
@@ -828,6 +1066,16 @@ export default class ContactCenter extends WebexPlugin implements IContactCenter
|
|
|
828
1066
|
};
|
|
829
1067
|
|
|
830
1068
|
this.webCallingService.setLoginOption(data.loginOption);
|
|
1069
|
+
if (this.agentConfig) {
|
|
1070
|
+
this.agentConfig.deviceType = data.loginOption;
|
|
1071
|
+
if (
|
|
1072
|
+
data.loginOption === LoginOption.AGENT_DN ||
|
|
1073
|
+
data.loginOption === LoginOption.EXTENSION
|
|
1074
|
+
) {
|
|
1075
|
+
this.agentConfig.defaultDn = data.dialNumber;
|
|
1076
|
+
this.agentConfig.dn = data.dialNumber;
|
|
1077
|
+
}
|
|
1078
|
+
}
|
|
831
1079
|
this.metricsManager.trackEvent(
|
|
832
1080
|
METRIC_EVENT_NAMES.STATION_LOGIN_SUCCESS,
|
|
833
1081
|
{
|
|
@@ -849,6 +1097,8 @@ export default class ContactCenter extends WebexPlugin implements IContactCenter
|
|
|
849
1097
|
}
|
|
850
1098
|
);
|
|
851
1099
|
|
|
1100
|
+
await this.ensureWxAppPostStationLogin();
|
|
1101
|
+
|
|
852
1102
|
return response;
|
|
853
1103
|
} catch (error) {
|
|
854
1104
|
const failure = error.details as Failure;
|
|
@@ -917,6 +1167,8 @@ export default class ContactCenter extends WebexPlugin implements IContactCenter
|
|
|
917
1167
|
this.webCallingService.deregisterWebCallingLine();
|
|
918
1168
|
}
|
|
919
1169
|
|
|
1170
|
+
await this.teardownWxAppLocalState();
|
|
1171
|
+
|
|
920
1172
|
LoggerProxy.log(`Agent station logout completed successfully`, {
|
|
921
1173
|
module: CC_FILE,
|
|
922
1174
|
method: METHODS.STATION_LOGOUT,
|
|
@@ -1172,6 +1424,454 @@ export default class ContactCenter extends WebexPlugin implements IContactCenter
|
|
|
1172
1424
|
}
|
|
1173
1425
|
};
|
|
1174
1426
|
|
|
1427
|
+
/**
|
|
1428
|
+
* Checks whether Mobius/WebRTC registration should be skipped by config
|
|
1429
|
+
* @returns {boolean} True when browser WebRTC registration is disabled
|
|
1430
|
+
* @private
|
|
1431
|
+
*/
|
|
1432
|
+
private isWebRTCRegistrationDisabled(): boolean {
|
|
1433
|
+
return this.$config?.disableWebRTCRegistration === true;
|
|
1434
|
+
}
|
|
1435
|
+
|
|
1436
|
+
/**
|
|
1437
|
+
* Validates contact-center plugin configuration before service initialization
|
|
1438
|
+
* @private
|
|
1439
|
+
*/
|
|
1440
|
+
private validatePluginConfig(): void {
|
|
1441
|
+
if (
|
|
1442
|
+
this.$config?.disableWebRTCRegistration === true &&
|
|
1443
|
+
this.$config?.allowMultiLogin === false
|
|
1444
|
+
) {
|
|
1445
|
+
throw new Error(
|
|
1446
|
+
'Invalid Contact Center configuration: disableWebRTCRegistration cannot be true when allowMultiLogin is false. Enable allowMultiLogin or allow WebRTC registration so an SDK instance can receive Mobius/WebRTC task events.'
|
|
1447
|
+
);
|
|
1448
|
+
}
|
|
1449
|
+
}
|
|
1450
|
+
|
|
1451
|
+
/**
|
|
1452
|
+
* Whether wxApp thick-client answer is enabled for this SDK instance.
|
|
1453
|
+
* @public
|
|
1454
|
+
*/
|
|
1455
|
+
public isWxBetterTogetherEnabled(): boolean {
|
|
1456
|
+
return this.$config?.enableWxBetterTogether === true;
|
|
1457
|
+
}
|
|
1458
|
+
|
|
1459
|
+
/**
|
|
1460
|
+
* Current station login option (Extension, Dial Number, or Browser/Desktop).
|
|
1461
|
+
* Prefer webCallingService — updated on every stationLogin before wxApp hooks run.
|
|
1462
|
+
* @private
|
|
1463
|
+
*/
|
|
1464
|
+
private getCurrentStationLoginOption(): LoginOption | undefined {
|
|
1465
|
+
return this.webCallingService?.loginOption ?? this.agentConfig?.deviceType;
|
|
1466
|
+
}
|
|
1467
|
+
|
|
1468
|
+
/**
|
|
1469
|
+
* wxApp thick-client answer is supported for Extension and Dial Number station login only —
|
|
1470
|
+
* not Browser/Desktop (WebRTC) login.
|
|
1471
|
+
* @private
|
|
1472
|
+
*/
|
|
1473
|
+
private assertWxAppStationLoginSupportedForEnable(): void {
|
|
1474
|
+
const loginOption = this.getCurrentStationLoginOption();
|
|
1475
|
+
if (loginOption !== LoginOption.EXTENSION && loginOption !== LoginOption.AGENT_DN) {
|
|
1476
|
+
throw new Error(
|
|
1477
|
+
'setManageWebexCallingInWxcc requires EXTENSION or AGENT_DN station login. Complete station login before enabling.'
|
|
1478
|
+
);
|
|
1479
|
+
}
|
|
1480
|
+
}
|
|
1481
|
+
|
|
1482
|
+
/**
|
|
1483
|
+
* Clears runtime wxApp config after logout/deregister so stale flags do not apply on relogin.
|
|
1484
|
+
* @private
|
|
1485
|
+
*/
|
|
1486
|
+
private resetEnableWxBetterTogetherConfig(): void {
|
|
1487
|
+
if (this.$config) {
|
|
1488
|
+
this.$config.enableWxBetterTogether = false;
|
|
1489
|
+
}
|
|
1490
|
+
this.taskManager.applyEnableWxBetterTogether(false);
|
|
1491
|
+
}
|
|
1492
|
+
|
|
1493
|
+
/**
|
|
1494
|
+
* Runtime enable/disable for wxApp Better Together (toast suppression + Mercury mute sync).
|
|
1495
|
+
*
|
|
1496
|
+
* **Phase 1 (WXCC-6026 / MMT): NOT part of the public host contract.**
|
|
1497
|
+
* Hosts must set `webexConfig.cc.enableWxBetterTogether` before `webex.init()` / `cc.register()`.
|
|
1498
|
+
* To change the flag after the SDK is initialized, re-init the SDK with the updated config.
|
|
1499
|
+
*
|
|
1500
|
+
* **Supported public read API:** {@link isWxBetterTogetherEnabled}.
|
|
1501
|
+
* **Supported telephony API:** unified `task.accept()`, `task.decline()`, `task.toggleMute()`,
|
|
1502
|
+
* `task.transmitDtmf()` — SDK routes wxApp calls internally when the init flag is active.
|
|
1503
|
+
*
|
|
1504
|
+
* **Production lifecycle does not call this method.** Station login, silent relogin, logout,
|
|
1505
|
+
* and deregister use {@link ensureWxAppPostStationLogin} and {@link teardownWxAppLocalState}
|
|
1506
|
+
* (usersub publish + Mercury subscribe/unsubscribe based on the init flag).
|
|
1507
|
+
*
|
|
1508
|
+
* This setter remains as a **private implementation** for Phase 2 runtime toggle and unit tests.
|
|
1509
|
+
* It updates `$config.enableWxBetterTogether`, TaskManager flags, cross-client usersub
|
|
1510
|
+
* (`answer-calls-on-wxcc`), and Mercury mute sync; rolls back config on publish/connect failure.
|
|
1511
|
+
*
|
|
1512
|
+
* @param enabled - `true` to enable wxApp answer + usersub suppression; `false` to disable and tear down.
|
|
1513
|
+
* @throws When enabling without login, on unsupported BROWSER station login, or when usersub/Mercury init fails.
|
|
1514
|
+
* @internal
|
|
1515
|
+
* @see enableWxBetterTogether (CCPluginConfig init flag)
|
|
1516
|
+
* @see ensureWxAppPostStationLogin
|
|
1517
|
+
* @see teardownWxAppLocalState
|
|
1518
|
+
*/
|
|
1519
|
+
private async setManageWebexCallingInWxcc(enabled: boolean): Promise<void> {
|
|
1520
|
+
if (enabled && !this.$webex.internal.device?.userId) {
|
|
1521
|
+
throw new Error('Cannot publish answer-calls-on-wxcc: user is not logged in');
|
|
1522
|
+
}
|
|
1523
|
+
|
|
1524
|
+
if (enabled) {
|
|
1525
|
+
this.assertWxAppStationLoginSupportedForEnable();
|
|
1526
|
+
}
|
|
1527
|
+
|
|
1528
|
+
const previousEnabled = this.isWxBetterTogetherEnabled();
|
|
1529
|
+
|
|
1530
|
+
if (this.$config) {
|
|
1531
|
+
this.$config.enableWxBetterTogether = enabled;
|
|
1532
|
+
}
|
|
1533
|
+
|
|
1534
|
+
this.taskManager.applyEnableWxBetterTogether(enabled);
|
|
1535
|
+
|
|
1536
|
+
let publishedEnable = false;
|
|
1537
|
+
|
|
1538
|
+
try {
|
|
1539
|
+
if (enabled) {
|
|
1540
|
+
await this.ensureWxAppMercuryAndSubscribe();
|
|
1541
|
+
await this.publishAnswerOnWebexCrossClientState(true);
|
|
1542
|
+
publishedEnable = true;
|
|
1543
|
+
this.taskManager.syncWxAppMuteFromCallDetailsForAllTasks();
|
|
1544
|
+
} else {
|
|
1545
|
+
await this.publishAnswerOnWebexCrossClientState(false);
|
|
1546
|
+
this.wxAppTelephonyMercurySync.unsubscribe();
|
|
1547
|
+
await this.releaseWxAppMercuryResources();
|
|
1548
|
+
}
|
|
1549
|
+
} catch (error) {
|
|
1550
|
+
if (publishedEnable) {
|
|
1551
|
+
await this.revertWxAppCrossClientPublish();
|
|
1552
|
+
} else if (enabled) {
|
|
1553
|
+
this.wxAppTelephonyMercurySync.unsubscribe();
|
|
1554
|
+
await this.releaseWxAppMercuryResources();
|
|
1555
|
+
}
|
|
1556
|
+
|
|
1557
|
+
if (this.$config) {
|
|
1558
|
+
this.$config.enableWxBetterTogether = previousEnabled;
|
|
1559
|
+
}
|
|
1560
|
+
this.taskManager.applyEnableWxBetterTogether(previousEnabled);
|
|
1561
|
+
throw error;
|
|
1562
|
+
}
|
|
1563
|
+
}
|
|
1564
|
+
|
|
1565
|
+
private async ensureWxAppPostStationLogin(): Promise<void> {
|
|
1566
|
+
if (this.getCurrentStationLoginOption() === LoginOption.BROWSER) {
|
|
1567
|
+
return;
|
|
1568
|
+
}
|
|
1569
|
+
|
|
1570
|
+
let publishedEnable = false;
|
|
1571
|
+
|
|
1572
|
+
try {
|
|
1573
|
+
if (this.isWxBetterTogetherEnabled()) {
|
|
1574
|
+
await this.ensureWxAppMercuryAndSubscribe();
|
|
1575
|
+
await this.publishAnswerOnWebexCrossClientState(true);
|
|
1576
|
+
publishedEnable = true;
|
|
1577
|
+
this.taskManager.syncWxAppMuteFromCallDetailsForAllTasks();
|
|
1578
|
+
} else {
|
|
1579
|
+
await this.ensureWxAppDeviceRegistered();
|
|
1580
|
+
await this.publishAnswerOnWebexCrossClientState(false, {force: true});
|
|
1581
|
+
this.webexCrossClientService.teardown();
|
|
1582
|
+
this.wxAppTelephonyMercurySync.unsubscribe();
|
|
1583
|
+
await this.releaseWxAppMercuryResources();
|
|
1584
|
+
}
|
|
1585
|
+
} catch (error) {
|
|
1586
|
+
LoggerProxy.error(`Failed to initialize wxApp post-station-login: ${error}`, {
|
|
1587
|
+
module: CC_FILE,
|
|
1588
|
+
method: METHODS.STATION_LOGIN,
|
|
1589
|
+
});
|
|
1590
|
+
|
|
1591
|
+
if (this.isWxBetterTogetherEnabled()) {
|
|
1592
|
+
if (publishedEnable) {
|
|
1593
|
+
await this.revertWxAppCrossClientPublish();
|
|
1594
|
+
} else {
|
|
1595
|
+
this.wxAppTelephonyMercurySync.unsubscribe();
|
|
1596
|
+
await this.releaseWxAppMercuryResources();
|
|
1597
|
+
}
|
|
1598
|
+
this.resetEnableWxBetterTogetherConfig();
|
|
1599
|
+
} else {
|
|
1600
|
+
this.scheduleForcedFalsePublishRetry();
|
|
1601
|
+
}
|
|
1602
|
+
}
|
|
1603
|
+
}
|
|
1604
|
+
|
|
1605
|
+
private clearWxAppFalsePublishRetryTimer(): void {
|
|
1606
|
+
if (this.wxAppFalsePublishRetryTimer) {
|
|
1607
|
+
clearTimeout(this.wxAppFalsePublishRetryTimer);
|
|
1608
|
+
this.wxAppFalsePublishRetryTimer = undefined;
|
|
1609
|
+
}
|
|
1610
|
+
}
|
|
1611
|
+
|
|
1612
|
+
private scheduleForcedFalsePublishRetry(retryAttempt = 0): void {
|
|
1613
|
+
this.scheduleFalsePublishRetry(retryAttempt, {requireDisabled: true});
|
|
1614
|
+
}
|
|
1615
|
+
|
|
1616
|
+
/**
|
|
1617
|
+
* Retries compensating false publish after rollback failure, regardless of enabled flag.
|
|
1618
|
+
* @private
|
|
1619
|
+
*/
|
|
1620
|
+
private scheduleCompensatingFalsePublishRetry(retryAttempt = 0): void {
|
|
1621
|
+
this.scheduleFalsePublishRetry(retryAttempt);
|
|
1622
|
+
}
|
|
1623
|
+
|
|
1624
|
+
private scheduleFalsePublishRetry(
|
|
1625
|
+
retryAttempt = 0,
|
|
1626
|
+
options: {requireDisabled?: boolean} = {}
|
|
1627
|
+
): void {
|
|
1628
|
+
if (retryAttempt >= ContactCenter.WXAPP_FALSE_PUBLISH_MAX_RETRIES) {
|
|
1629
|
+
return;
|
|
1630
|
+
}
|
|
1631
|
+
|
|
1632
|
+
if (options?.requireDisabled && this.isWxBetterTogetherEnabled()) {
|
|
1633
|
+
return;
|
|
1634
|
+
}
|
|
1635
|
+
|
|
1636
|
+
this.clearWxAppFalsePublishRetryTimer();
|
|
1637
|
+
|
|
1638
|
+
this.wxAppFalsePublishRetryTimer = setTimeout(async () => {
|
|
1639
|
+
this.wxAppFalsePublishRetryTimer = undefined;
|
|
1640
|
+
|
|
1641
|
+
if (options?.requireDisabled && this.isWxBetterTogetherEnabled()) {
|
|
1642
|
+
return;
|
|
1643
|
+
}
|
|
1644
|
+
|
|
1645
|
+
if (
|
|
1646
|
+
!options?.requireDisabled &&
|
|
1647
|
+
this.isWxBetterTogetherEnabled() &&
|
|
1648
|
+
this.webexCrossClientService.isAnswerCallsStateActive()
|
|
1649
|
+
) {
|
|
1650
|
+
return;
|
|
1651
|
+
}
|
|
1652
|
+
|
|
1653
|
+
try {
|
|
1654
|
+
await this.ensureWxAppDeviceRegistered();
|
|
1655
|
+
await this.publishAnswerOnWebexCrossClientState(false, {force: true});
|
|
1656
|
+
this.webexCrossClientService.teardown();
|
|
1657
|
+
this.wxAppTelephonyMercurySync.unsubscribe();
|
|
1658
|
+
await this.releaseWxAppMercuryResources();
|
|
1659
|
+
} catch (retryError) {
|
|
1660
|
+
LoggerProxy.error(
|
|
1661
|
+
`Failed to retry forced answer-calls-on-wxcc false publish: ${retryError}`,
|
|
1662
|
+
{
|
|
1663
|
+
module: CC_FILE,
|
|
1664
|
+
method: METHODS.SET_MANAGE_WEBEX_CALLING_IN_WXCC,
|
|
1665
|
+
}
|
|
1666
|
+
);
|
|
1667
|
+
this.scheduleFalsePublishRetry(retryAttempt + 1, options);
|
|
1668
|
+
}
|
|
1669
|
+
}, ContactCenter.WXAPP_FALSE_PUBLISH_RETRY_DELAY_MS);
|
|
1670
|
+
}
|
|
1671
|
+
|
|
1672
|
+
/**
|
|
1673
|
+
* Best-effort rollback when usersub true was published but wxApp setup did not complete.
|
|
1674
|
+
* @private
|
|
1675
|
+
*/
|
|
1676
|
+
private async revertWxAppCrossClientPublish(): Promise<void> {
|
|
1677
|
+
try {
|
|
1678
|
+
await this.publishAnswerOnWebexCrossClientState(false, {force: true});
|
|
1679
|
+
} catch (error) {
|
|
1680
|
+
LoggerProxy.error(
|
|
1681
|
+
`Failed to publish compensating answer-calls-on-wxcc false during wxApp rollback: ${error}`,
|
|
1682
|
+
{
|
|
1683
|
+
module: CC_FILE,
|
|
1684
|
+
method: METHODS.SET_MANAGE_WEBEX_CALLING_IN_WXCC,
|
|
1685
|
+
}
|
|
1686
|
+
);
|
|
1687
|
+
this.scheduleCompensatingFalsePublishRetry();
|
|
1688
|
+
}
|
|
1689
|
+
|
|
1690
|
+
this.webexCrossClientService.teardown();
|
|
1691
|
+
this.wxAppTelephonyMercurySync.unsubscribe();
|
|
1692
|
+
await this.releaseWxAppMercuryResources();
|
|
1693
|
+
}
|
|
1694
|
+
|
|
1695
|
+
private async ensureWxAppDeviceRegistered(): Promise<void> {
|
|
1696
|
+
const device = this.$webex.internal.device;
|
|
1697
|
+
|
|
1698
|
+
if (device && !device.registered && device.register) {
|
|
1699
|
+
await device.register();
|
|
1700
|
+
this.wxAppDeviceRegisteredByCc = true;
|
|
1701
|
+
LoggerProxy.log('WxApp: device registered for cross-client publish', {
|
|
1702
|
+
module: CC_FILE,
|
|
1703
|
+
method: METHODS.ENSURE_WXAPP_MERCURY_CONNECTED,
|
|
1704
|
+
});
|
|
1705
|
+
}
|
|
1706
|
+
}
|
|
1707
|
+
|
|
1708
|
+
private async ensureWxAppMercuryConnected(): Promise<void> {
|
|
1709
|
+
const mercury = this.$webex.internal.mercury;
|
|
1710
|
+
|
|
1711
|
+
await this.ensureWxAppDeviceRegistered();
|
|
1712
|
+
|
|
1713
|
+
if (mercury && !mercury.connected) {
|
|
1714
|
+
await mercury.connect();
|
|
1715
|
+
this.wxAppMercuryConnectedByCc = true;
|
|
1716
|
+
LoggerProxy.log('WxApp mute sync: mercury connected', {
|
|
1717
|
+
module: CC_FILE,
|
|
1718
|
+
method: METHODS.ENSURE_WXAPP_MERCURY_CONNECTED,
|
|
1719
|
+
});
|
|
1720
|
+
}
|
|
1721
|
+
}
|
|
1722
|
+
|
|
1723
|
+
/**
|
|
1724
|
+
* Disconnects Mercury and unregisters the device when wxApp mute sync opened them.
|
|
1725
|
+
* @private
|
|
1726
|
+
*/
|
|
1727
|
+
private async releaseWxAppMercuryResources(): Promise<void> {
|
|
1728
|
+
const mercury = this.$webex.internal.mercury;
|
|
1729
|
+
const device = this.$webex.internal.device;
|
|
1730
|
+
|
|
1731
|
+
if (this.wxAppMercuryConnectedByCc && mercury?.connected) {
|
|
1732
|
+
try {
|
|
1733
|
+
await mercury.disconnect();
|
|
1734
|
+
this.wxAppMercuryConnectedByCc = false;
|
|
1735
|
+
LoggerProxy.log('WxApp mute sync: mercury disconnected', {
|
|
1736
|
+
module: CC_FILE,
|
|
1737
|
+
method: METHODS.ENSURE_WXAPP_MERCURY_CONNECTED,
|
|
1738
|
+
});
|
|
1739
|
+
} catch (error) {
|
|
1740
|
+
LoggerProxy.error(`Failed to disconnect wxApp Mercury: ${error}`, {
|
|
1741
|
+
module: CC_FILE,
|
|
1742
|
+
method: METHODS.ENSURE_WXAPP_MERCURY_CONNECTED,
|
|
1743
|
+
});
|
|
1744
|
+
}
|
|
1745
|
+
}
|
|
1746
|
+
|
|
1747
|
+
if (this.wxAppDeviceRegisteredByCc && device?.registered && device.unregister) {
|
|
1748
|
+
try {
|
|
1749
|
+
// @ts-ignore
|
|
1750
|
+
await device.unregister();
|
|
1751
|
+
this.wxAppDeviceRegisteredByCc = false;
|
|
1752
|
+
LoggerProxy.log('WxApp mute sync: device unregistered', {
|
|
1753
|
+
module: CC_FILE,
|
|
1754
|
+
method: METHODS.ENSURE_WXAPP_MERCURY_CONNECTED,
|
|
1755
|
+
});
|
|
1756
|
+
} catch (error) {
|
|
1757
|
+
LoggerProxy.error(`Failed to unregister wxApp device: ${error}`, {
|
|
1758
|
+
module: CC_FILE,
|
|
1759
|
+
method: METHODS.ENSURE_WXAPP_MERCURY_CONNECTED,
|
|
1760
|
+
});
|
|
1761
|
+
}
|
|
1762
|
+
} else if (this.wxAppDeviceRegisteredByCc) {
|
|
1763
|
+
this.wxAppDeviceRegisteredByCc = false;
|
|
1764
|
+
}
|
|
1765
|
+
}
|
|
1766
|
+
|
|
1767
|
+
/**
|
|
1768
|
+
* Clears wxApp runtime state and feature-owned resources. Publish failures are logged;
|
|
1769
|
+
* optional rethrow for deregister when callers need to surface usersub errors.
|
|
1770
|
+
* @private
|
|
1771
|
+
*/
|
|
1772
|
+
private async teardownWxAppLocalState(options?: {
|
|
1773
|
+
rethrowPublishError?: boolean;
|
|
1774
|
+
clearInitFlag?: boolean;
|
|
1775
|
+
}): Promise<{publishError?: unknown}> {
|
|
1776
|
+
this.clearWxAppFalsePublishRetryTimer();
|
|
1777
|
+
let publishError: unknown;
|
|
1778
|
+
|
|
1779
|
+
try {
|
|
1780
|
+
const shouldForceFalsePublish =
|
|
1781
|
+
this.isWxBetterTogetherEnabled() || this.webexCrossClientService.isAnswerCallsStateActive();
|
|
1782
|
+
|
|
1783
|
+
await this.publishAnswerOnWebexCrossClientState(false, {
|
|
1784
|
+
force: shouldForceFalsePublish,
|
|
1785
|
+
});
|
|
1786
|
+
} catch (error) {
|
|
1787
|
+
publishError = error;
|
|
1788
|
+
LoggerProxy.error(
|
|
1789
|
+
`Failed to publish answer-calls-on-wxcc false during wxApp teardown: ${error}`,
|
|
1790
|
+
{
|
|
1791
|
+
module: CC_FILE,
|
|
1792
|
+
method: METHODS.SET_MANAGE_WEBEX_CALLING_IN_WXCC,
|
|
1793
|
+
}
|
|
1794
|
+
);
|
|
1795
|
+
}
|
|
1796
|
+
|
|
1797
|
+
this.webexCrossClientService.teardown();
|
|
1798
|
+
this.wxAppTelephonyMercurySync.unsubscribe();
|
|
1799
|
+
await this.releaseWxAppMercuryResources();
|
|
1800
|
+
|
|
1801
|
+
if (options?.clearInitFlag) {
|
|
1802
|
+
this.resetEnableWxBetterTogetherConfig();
|
|
1803
|
+
}
|
|
1804
|
+
|
|
1805
|
+
if (publishError) {
|
|
1806
|
+
this.scheduleCompensatingFalsePublishRetry();
|
|
1807
|
+
}
|
|
1808
|
+
|
|
1809
|
+
if (options?.rethrowPublishError && publishError) {
|
|
1810
|
+
throw publishError;
|
|
1811
|
+
}
|
|
1812
|
+
|
|
1813
|
+
return {publishError: publishError ?? undefined};
|
|
1814
|
+
}
|
|
1815
|
+
|
|
1816
|
+
private async ensureWxAppMercuryAndSubscribe(): Promise<void> {
|
|
1817
|
+
if (!this.isWxBetterTogetherEnabled()) {
|
|
1818
|
+
return;
|
|
1819
|
+
}
|
|
1820
|
+
|
|
1821
|
+
if (this.getCurrentStationLoginOption() === LoginOption.BROWSER) {
|
|
1822
|
+
return;
|
|
1823
|
+
}
|
|
1824
|
+
|
|
1825
|
+
const agentId = this.agentConfig?.agentId;
|
|
1826
|
+
if (!agentId) {
|
|
1827
|
+
LoggerProxy.error('Cannot subscribe wxApp mute sync: agentId unavailable', {
|
|
1828
|
+
module: CC_FILE,
|
|
1829
|
+
method: METHODS.SYNC_WXAPP_MUTE_FROM_MERCURY,
|
|
1830
|
+
});
|
|
1831
|
+
|
|
1832
|
+
return;
|
|
1833
|
+
}
|
|
1834
|
+
|
|
1835
|
+
try {
|
|
1836
|
+
await this.ensureWxAppMercuryConnected();
|
|
1837
|
+
this.wxAppTelephonyMercurySync.subscribe(agentId, (callId, muted) => {
|
|
1838
|
+
this.taskManager.applyWxAppMuteStateFromSync(callId, muted);
|
|
1839
|
+
});
|
|
1840
|
+
} catch (error) {
|
|
1841
|
+
LoggerProxy.error(`Failed to ensure wxApp Mercury mute sync: ${error}`, {
|
|
1842
|
+
module: CC_FILE,
|
|
1843
|
+
method: METHODS.SYNC_WXAPP_MUTE_FROM_MERCURY,
|
|
1844
|
+
});
|
|
1845
|
+
this.wxAppTelephonyMercurySync.unsubscribe();
|
|
1846
|
+
await this.releaseWxAppMercuryResources();
|
|
1847
|
+
throw error;
|
|
1848
|
+
}
|
|
1849
|
+
}
|
|
1850
|
+
|
|
1851
|
+
private async publishAnswerOnWebexCrossClientState(
|
|
1852
|
+
enable: boolean,
|
|
1853
|
+
options?: {force?: boolean}
|
|
1854
|
+
): Promise<void> {
|
|
1855
|
+
if (enable && !this.isWxBetterTogetherEnabled()) {
|
|
1856
|
+
return;
|
|
1857
|
+
}
|
|
1858
|
+
|
|
1859
|
+
if (!enable && !options?.force && !this.webexCrossClientService.isAnswerCallsStateActive()) {
|
|
1860
|
+
return;
|
|
1861
|
+
}
|
|
1862
|
+
|
|
1863
|
+
const userId = this.$webex.internal.device?.userId;
|
|
1864
|
+
if (!userId) {
|
|
1865
|
+
return;
|
|
1866
|
+
}
|
|
1867
|
+
|
|
1868
|
+
await this.webexCrossClientService.setManageWebexCallingInWxcc(enable, {userId});
|
|
1869
|
+
|
|
1870
|
+
if (enable) {
|
|
1871
|
+
this.clearWxAppFalsePublishRetryTimer();
|
|
1872
|
+
}
|
|
1873
|
+
}
|
|
1874
|
+
|
|
1175
1875
|
/**
|
|
1176
1876
|
* Initializes event listeners for the Contact Center service
|
|
1177
1877
|
* Sets up handlers for connection state changes and other core events
|
|
@@ -1203,13 +1903,13 @@ export default class ContactCenter extends WebexPlugin implements IContactCenter
|
|
|
1203
1903
|
private async handleConnectionLost(msg: ConnectionLostDetails): Promise<void> {
|
|
1204
1904
|
if (msg.isConnectionLost) {
|
|
1205
1905
|
// TODO: Emit an event saying connection is lost
|
|
1206
|
-
LoggerProxy.
|
|
1906
|
+
LoggerProxy.log('event=handleConnectionLost | Connection lost', {
|
|
1207
1907
|
module: CC_FILE,
|
|
1208
1908
|
method: METHODS.HANDLE_CONNECTION_LOST,
|
|
1209
1909
|
});
|
|
1210
1910
|
} else if (msg.isSocketReconnected) {
|
|
1211
1911
|
// TODO: Emit an event saying connection is re-estabilished
|
|
1212
|
-
LoggerProxy.
|
|
1912
|
+
LoggerProxy.log(
|
|
1213
1913
|
'event=handleConnectionReconnect | Connection reconnected attempting to request silent relogin',
|
|
1214
1914
|
{module: CC_FILE, method: METHODS.HANDLE_CONNECTION_LOST}
|
|
1215
1915
|
);
|
|
@@ -1224,7 +1924,7 @@ export default class ContactCenter extends WebexPlugin implements IContactCenter
|
|
|
1224
1924
|
* @private
|
|
1225
1925
|
*/
|
|
1226
1926
|
private async silentRelogin(): Promise<void> {
|
|
1227
|
-
LoggerProxy.
|
|
1927
|
+
LoggerProxy.log('Starting silent relogin process', {
|
|
1228
1928
|
module: CC_FILE,
|
|
1229
1929
|
method: METHODS.SILENT_RELOGIN,
|
|
1230
1930
|
});
|
|
@@ -1246,7 +1946,7 @@ export default class ContactCenter extends WebexPlugin implements IContactCenter
|
|
|
1246
1946
|
await this.handleDeviceType(deviceType as LoginOption, dn);
|
|
1247
1947
|
|
|
1248
1948
|
if (lastStateChangeReason === 'agent-wss-disconnect') {
|
|
1249
|
-
LoggerProxy.
|
|
1949
|
+
LoggerProxy.log(
|
|
1250
1950
|
'event=requestAutoStateChange | Requesting state change to available on socket reconnect',
|
|
1251
1951
|
{module: CC_FILE, method: METHODS.SILENT_RELOGIN}
|
|
1252
1952
|
);
|
|
@@ -1275,8 +1975,8 @@ export default class ContactCenter extends WebexPlugin implements IContactCenter
|
|
|
1275
1975
|
}
|
|
1276
1976
|
this.agentConfig.lastStateAuxCodeId = auxCodeId;
|
|
1277
1977
|
this.agentConfig.isAgentLoggedIn = true;
|
|
1278
|
-
|
|
1279
|
-
this.
|
|
1978
|
+
|
|
1979
|
+
await this.ensureWxAppPostStationLogin();
|
|
1280
1980
|
|
|
1281
1981
|
LoggerProxy.log(
|
|
1282
1982
|
`Silent relogin process completed successfully with login Option: ${reLoginResponse.data.deviceType} teamId: ${reLoginResponse.data.teamId}`,
|
|
@@ -1317,6 +2017,16 @@ export default class ContactCenter extends WebexPlugin implements IContactCenter
|
|
|
1317
2017
|
this.agentConfig.deviceType = deviceType;
|
|
1318
2018
|
switch (deviceType) {
|
|
1319
2019
|
case LoginOption.BROWSER:
|
|
2020
|
+
if (this.isWebRTCRegistrationDisabled()) {
|
|
2021
|
+
LoggerProxy.info(
|
|
2022
|
+
'Skipping web calling line registration because disableWebRTCRegistration is enabled',
|
|
2023
|
+
{
|
|
2024
|
+
module: CC_FILE,
|
|
2025
|
+
method: METHODS.HANDLE_DEVICE_TYPE,
|
|
2026
|
+
}
|
|
2027
|
+
);
|
|
2028
|
+
break;
|
|
2029
|
+
}
|
|
1320
2030
|
try {
|
|
1321
2031
|
await this.webCallingService.registerWebCallingLine();
|
|
1322
2032
|
} catch (error) {
|
|
@@ -1509,6 +2219,239 @@ export default class ContactCenter extends WebexPlugin implements IContactCenter
|
|
|
1509
2219
|
}
|
|
1510
2220
|
}
|
|
1511
2221
|
|
|
2222
|
+
/**
|
|
2223
|
+
* Accepts a campaign preview contact, initiating the outbound call.
|
|
2224
|
+
*
|
|
2225
|
+
* When a campaign manager reserves a contact for an agent, the agent receives an
|
|
2226
|
+
* `AgentOfferCampaignReservation` event. The agent can then accept the preview contact
|
|
2227
|
+
* to initiate the outbound call.
|
|
2228
|
+
*
|
|
2229
|
+
* @param {PreviewContactPayload} payload - The preview contact payload containing interactionId and campaignId (campaign name, not UUID).
|
|
2230
|
+
* @returns {Promise<TaskResponse>} Promise resolving with agent contact on success.
|
|
2231
|
+
* @throws {Error} If the operation fails (network error, customer unavailable, etc.)
|
|
2232
|
+
*
|
|
2233
|
+
* @example
|
|
2234
|
+
* ```typescript
|
|
2235
|
+
* webex.cc.on('task:campaignPreviewReservation', async (task) => {
|
|
2236
|
+
* const { interactionId } = task.data;
|
|
2237
|
+
* // campaignId is the campaign name (e.g. "MyCampaign"), not a UUID
|
|
2238
|
+
* const campaignId = task.data.interaction.callProcessingDetails.campaignId;
|
|
2239
|
+
*
|
|
2240
|
+
* const result = await webex.cc.acceptPreviewContact({ interactionId, campaignId });
|
|
2241
|
+
* });
|
|
2242
|
+
* ```
|
|
2243
|
+
*/
|
|
2244
|
+
public async acceptPreviewContact(payload: PreviewContactPayload): Promise<TaskResponse> {
|
|
2245
|
+
LoggerProxy.info('Accepting campaign preview contact', {
|
|
2246
|
+
module: CC_FILE,
|
|
2247
|
+
method: METHODS.ACCEPT_PREVIEW_CONTACT,
|
|
2248
|
+
});
|
|
2249
|
+
try {
|
|
2250
|
+
this.metricsManager.timeEvent([
|
|
2251
|
+
METRIC_EVENT_NAMES.CAMPAIGN_PREVIEW_ACCEPT_SUCCESS,
|
|
2252
|
+
METRIC_EVENT_NAMES.CAMPAIGN_PREVIEW_ACCEPT_FAILED,
|
|
2253
|
+
]);
|
|
2254
|
+
|
|
2255
|
+
const result = await this.services.dialer.acceptPreviewContact({data: payload});
|
|
2256
|
+
|
|
2257
|
+
this.metricsManager.trackEvent(
|
|
2258
|
+
METRIC_EVENT_NAMES.CAMPAIGN_PREVIEW_ACCEPT_SUCCESS,
|
|
2259
|
+
{
|
|
2260
|
+
...MetricsManager.getCommonTrackingFieldForAQMResponse(result),
|
|
2261
|
+
interactionId: payload.interactionId,
|
|
2262
|
+
campaignId: payload.campaignId,
|
|
2263
|
+
},
|
|
2264
|
+
['behavioral', 'business', 'operational']
|
|
2265
|
+
);
|
|
2266
|
+
|
|
2267
|
+
LoggerProxy.log('Campaign preview contact accepted successfully', {
|
|
2268
|
+
module: CC_FILE,
|
|
2269
|
+
method: METHODS.ACCEPT_PREVIEW_CONTACT,
|
|
2270
|
+
trackingId: result.trackingId,
|
|
2271
|
+
interactionId: payload.interactionId,
|
|
2272
|
+
});
|
|
2273
|
+
|
|
2274
|
+
return result;
|
|
2275
|
+
} catch (error) {
|
|
2276
|
+
const failure = error.details as Failure;
|
|
2277
|
+
this.metricsManager.trackEvent(
|
|
2278
|
+
METRIC_EVENT_NAMES.CAMPAIGN_PREVIEW_ACCEPT_FAILED,
|
|
2279
|
+
{
|
|
2280
|
+
...MetricsManager.getCommonTrackingFieldForAQMResponseFailed(failure),
|
|
2281
|
+
interactionId: payload.interactionId,
|
|
2282
|
+
campaignId: payload.campaignId,
|
|
2283
|
+
},
|
|
2284
|
+
['behavioral', 'business', 'operational']
|
|
2285
|
+
);
|
|
2286
|
+
const {error: detailedError} = getErrorDetails(
|
|
2287
|
+
error,
|
|
2288
|
+
METHODS.ACCEPT_PREVIEW_CONTACT,
|
|
2289
|
+
CC_FILE
|
|
2290
|
+
);
|
|
2291
|
+
throw detailedError;
|
|
2292
|
+
}
|
|
2293
|
+
}
|
|
2294
|
+
|
|
2295
|
+
/**
|
|
2296
|
+
* Skips a campaign preview contact, requesting the next contact from the campaign.
|
|
2297
|
+
*
|
|
2298
|
+
* When a campaign manager reserves a contact for an agent, the agent receives an
|
|
2299
|
+
* `AgentOfferCampaignReservation` event. Instead of accepting, the agent can skip the
|
|
2300
|
+
* preview contact to move to the next contact in the campaign.
|
|
2301
|
+
*
|
|
2302
|
+
* @param {PreviewContactPayload} payload - The preview contact payload containing interactionId and campaignId (campaign name, not UUID).
|
|
2303
|
+
* @returns {Promise<TaskResponse>} Promise resolving with agent contact on success.
|
|
2304
|
+
* @throws {Error} If the operation fails (network error, etc.)
|
|
2305
|
+
*
|
|
2306
|
+
* @example
|
|
2307
|
+
* ```typescript
|
|
2308
|
+
* webex.cc.on('task:campaignPreviewReservation', async (task) => {
|
|
2309
|
+
* const { interactionId } = task.data;
|
|
2310
|
+
* const campaignId = task.data.interaction.callProcessingDetails.campaignId;
|
|
2311
|
+
*
|
|
2312
|
+
* const result = await webex.cc.skipPreviewContact({ interactionId, campaignId });
|
|
2313
|
+
* });
|
|
2314
|
+
* ```
|
|
2315
|
+
*/
|
|
2316
|
+
public async skipPreviewContact(payload: PreviewContactPayload): Promise<TaskResponse> {
|
|
2317
|
+
const task = this.taskManager.getTask(payload.interactionId);
|
|
2318
|
+
if (task?.data?.interaction?.callProcessingDetails?.campaignPreviewSkipDisabled === 'true') {
|
|
2319
|
+
LoggerProxy.warn('Skip action is disabled for this campaign preview contact', {
|
|
2320
|
+
module: CC_FILE,
|
|
2321
|
+
method: METHODS.SKIP_PREVIEW_CONTACT,
|
|
2322
|
+
interactionId: payload.interactionId,
|
|
2323
|
+
});
|
|
2324
|
+
throw new Error('Skip action is disabled for this campaign preview contact');
|
|
2325
|
+
}
|
|
2326
|
+
|
|
2327
|
+
LoggerProxy.info('Skipping campaign preview contact', {
|
|
2328
|
+
module: CC_FILE,
|
|
2329
|
+
method: METHODS.SKIP_PREVIEW_CONTACT,
|
|
2330
|
+
});
|
|
2331
|
+
try {
|
|
2332
|
+
this.metricsManager.timeEvent([
|
|
2333
|
+
METRIC_EVENT_NAMES.CAMPAIGN_PREVIEW_SKIP_SUCCESS,
|
|
2334
|
+
METRIC_EVENT_NAMES.CAMPAIGN_PREVIEW_SKIP_FAILED,
|
|
2335
|
+
]);
|
|
2336
|
+
|
|
2337
|
+
const result = await this.services.dialer.skipPreviewContact({data: payload});
|
|
2338
|
+
|
|
2339
|
+
this.metricsManager.trackEvent(
|
|
2340
|
+
METRIC_EVENT_NAMES.CAMPAIGN_PREVIEW_SKIP_SUCCESS,
|
|
2341
|
+
{
|
|
2342
|
+
...MetricsManager.getCommonTrackingFieldForAQMResponse(result),
|
|
2343
|
+
interactionId: payload.interactionId,
|
|
2344
|
+
campaignId: payload.campaignId,
|
|
2345
|
+
},
|
|
2346
|
+
['behavioral', 'business', 'operational']
|
|
2347
|
+
);
|
|
2348
|
+
|
|
2349
|
+
LoggerProxy.log('Campaign preview contact skipped successfully', {
|
|
2350
|
+
module: CC_FILE,
|
|
2351
|
+
method: METHODS.SKIP_PREVIEW_CONTACT,
|
|
2352
|
+
trackingId: result.trackingId,
|
|
2353
|
+
interactionId: payload.interactionId,
|
|
2354
|
+
});
|
|
2355
|
+
|
|
2356
|
+
return result;
|
|
2357
|
+
} catch (error) {
|
|
2358
|
+
const failure = error.details as Failure;
|
|
2359
|
+
this.metricsManager.trackEvent(
|
|
2360
|
+
METRIC_EVENT_NAMES.CAMPAIGN_PREVIEW_SKIP_FAILED,
|
|
2361
|
+
{
|
|
2362
|
+
...MetricsManager.getCommonTrackingFieldForAQMResponseFailed(failure),
|
|
2363
|
+
interactionId: payload.interactionId,
|
|
2364
|
+
campaignId: payload.campaignId,
|
|
2365
|
+
},
|
|
2366
|
+
['behavioral', 'business', 'operational']
|
|
2367
|
+
);
|
|
2368
|
+
const {error: detailedError} = getErrorDetails(error, METHODS.SKIP_PREVIEW_CONTACT, CC_FILE);
|
|
2369
|
+
throw detailedError;
|
|
2370
|
+
}
|
|
2371
|
+
}
|
|
2372
|
+
|
|
2373
|
+
/**
|
|
2374
|
+
* Removes a campaign preview contact from the campaign list entirely.
|
|
2375
|
+
*
|
|
2376
|
+
* When a campaign manager reserves a contact for an agent, the agent receives an
|
|
2377
|
+
* `AgentOfferCampaignReservation` event. Instead of accepting or skipping, the agent can
|
|
2378
|
+
* remove the preview contact to permanently take it out of the campaign contact list.
|
|
2379
|
+
*
|
|
2380
|
+
* @param {PreviewContactPayload} payload - The preview contact payload containing interactionId and campaignId (campaign name, not UUID).
|
|
2381
|
+
* @returns {Promise<TaskResponse>} Promise resolving with agent contact on success.
|
|
2382
|
+
* @throws {Error} If the operation fails (network error, etc.)
|
|
2383
|
+
*
|
|
2384
|
+
* @example
|
|
2385
|
+
* ```typescript
|
|
2386
|
+
* webex.cc.on('task:campaignPreviewReservation', async (task) => {
|
|
2387
|
+
* const { interactionId } = task.data;
|
|
2388
|
+
* const campaignId = task.data.interaction.callProcessingDetails.campaignId;
|
|
2389
|
+
*
|
|
2390
|
+
* const result = await webex.cc.removePreviewContact({ interactionId, campaignId });
|
|
2391
|
+
* });
|
|
2392
|
+
* ```
|
|
2393
|
+
*/
|
|
2394
|
+
public async removePreviewContact(payload: PreviewContactPayload): Promise<TaskResponse> {
|
|
2395
|
+
const task = this.taskManager.getTask(payload.interactionId);
|
|
2396
|
+
if (task?.data?.interaction?.callProcessingDetails?.campaignPreviewRemoveDisabled === 'true') {
|
|
2397
|
+
LoggerProxy.warn('Remove action is disabled for this campaign preview contact', {
|
|
2398
|
+
module: CC_FILE,
|
|
2399
|
+
method: METHODS.REMOVE_PREVIEW_CONTACT,
|
|
2400
|
+
interactionId: payload.interactionId,
|
|
2401
|
+
});
|
|
2402
|
+
throw new Error('Remove action is disabled for this campaign preview contact');
|
|
2403
|
+
}
|
|
2404
|
+
|
|
2405
|
+
LoggerProxy.info('Removing campaign preview contact', {
|
|
2406
|
+
module: CC_FILE,
|
|
2407
|
+
method: METHODS.REMOVE_PREVIEW_CONTACT,
|
|
2408
|
+
});
|
|
2409
|
+
try {
|
|
2410
|
+
this.metricsManager.timeEvent([
|
|
2411
|
+
METRIC_EVENT_NAMES.CAMPAIGN_PREVIEW_REMOVE_SUCCESS,
|
|
2412
|
+
METRIC_EVENT_NAMES.CAMPAIGN_PREVIEW_REMOVE_FAILED,
|
|
2413
|
+
]);
|
|
2414
|
+
|
|
2415
|
+
const result = await this.services.dialer.removePreviewContact({data: payload});
|
|
2416
|
+
|
|
2417
|
+
this.metricsManager.trackEvent(
|
|
2418
|
+
METRIC_EVENT_NAMES.CAMPAIGN_PREVIEW_REMOVE_SUCCESS,
|
|
2419
|
+
{
|
|
2420
|
+
...MetricsManager.getCommonTrackingFieldForAQMResponse(result),
|
|
2421
|
+
interactionId: payload.interactionId,
|
|
2422
|
+
campaignId: payload.campaignId,
|
|
2423
|
+
},
|
|
2424
|
+
['behavioral', 'business', 'operational']
|
|
2425
|
+
);
|
|
2426
|
+
|
|
2427
|
+
LoggerProxy.log('Campaign preview contact removed successfully', {
|
|
2428
|
+
module: CC_FILE,
|
|
2429
|
+
method: METHODS.REMOVE_PREVIEW_CONTACT,
|
|
2430
|
+
trackingId: result.trackingId,
|
|
2431
|
+
interactionId: payload.interactionId,
|
|
2432
|
+
});
|
|
2433
|
+
|
|
2434
|
+
return result;
|
|
2435
|
+
} catch (error) {
|
|
2436
|
+
const failure = error.details as Failure;
|
|
2437
|
+
this.metricsManager.trackEvent(
|
|
2438
|
+
METRIC_EVENT_NAMES.CAMPAIGN_PREVIEW_REMOVE_FAILED,
|
|
2439
|
+
{
|
|
2440
|
+
...MetricsManager.getCommonTrackingFieldForAQMResponseFailed(failure),
|
|
2441
|
+
interactionId: payload.interactionId,
|
|
2442
|
+
campaignId: payload.campaignId,
|
|
2443
|
+
},
|
|
2444
|
+
['behavioral', 'business', 'operational']
|
|
2445
|
+
);
|
|
2446
|
+
const {error: detailedError} = getErrorDetails(
|
|
2447
|
+
error,
|
|
2448
|
+
METHODS.REMOVE_PREVIEW_CONTACT,
|
|
2449
|
+
CC_FILE
|
|
2450
|
+
);
|
|
2451
|
+
throw detailedError;
|
|
2452
|
+
}
|
|
2453
|
+
}
|
|
2454
|
+
|
|
1512
2455
|
/**
|
|
1513
2456
|
* Fetches outdial ANI (Automatic Number Identification) entries for an outdial ANI ID.
|
|
1514
2457
|
*
|
|
@@ -1656,6 +2599,7 @@ export default class ContactCenter extends WebexPlugin implements IContactCenter
|
|
|
1656
2599
|
/**
|
|
1657
2600
|
* Updates the agent device type and login configuration.
|
|
1658
2601
|
* Use this method to change how an agent connects to the contact center system (e.g., switching from browser-based calling to a desk phone extension).
|
|
2602
|
+
* Change to any field of the profile is allowed;
|
|
1659
2603
|
*
|
|
1660
2604
|
* @param {AgentDeviceUpdate} data Configuration containing:
|
|
1661
2605
|
* - loginOption: New device type ('BROWSER', 'EXTENSION', 'AGENT_DN')
|
|
@@ -1695,29 +2639,8 @@ export default class ContactCenter extends WebexPlugin implements IContactCenter
|
|
|
1695
2639
|
});
|
|
1696
2640
|
|
|
1697
2641
|
try {
|
|
1698
|
-
// Only block if both loginOption AND teamId remain unchanged
|
|
1699
|
-
if (
|
|
1700
|
-
this.webCallingService?.loginOption === data.loginOption &&
|
|
1701
|
-
data.teamId === this.agentConfig.currentTeamId
|
|
1702
|
-
) {
|
|
1703
|
-
const message =
|
|
1704
|
-
'Will not proceed with device update as new Device type is same as current device type and teamId is same as current teamId';
|
|
1705
|
-
const err = new Error(message) as GenericError;
|
|
1706
|
-
err.details = {
|
|
1707
|
-
type: 'Identical Device Change Failure',
|
|
1708
|
-
orgId: this.$webex.credentials.getOrgId(),
|
|
1709
|
-
trackingId,
|
|
1710
|
-
data: {
|
|
1711
|
-
agentId: this.agentConfig.agentId,
|
|
1712
|
-
reasonCode: 'R002',
|
|
1713
|
-
reason: message,
|
|
1714
|
-
},
|
|
1715
|
-
};
|
|
1716
|
-
throw err;
|
|
1717
|
-
}
|
|
1718
|
-
|
|
1719
2642
|
await this.stationLogout({
|
|
1720
|
-
logoutReason: 'User requested agent
|
|
2643
|
+
logoutReason: 'User requested agent profile update',
|
|
1721
2644
|
});
|
|
1722
2645
|
|
|
1723
2646
|
const loginPayload: AgentLogin = {
|
|
@@ -1773,8 +2696,8 @@ export default class ContactCenter extends WebexPlugin implements IContactCenter
|
|
|
1773
2696
|
}
|
|
1774
2697
|
|
|
1775
2698
|
/**
|
|
1776
|
-
* Returns paginated entry points
|
|
1777
|
-
*
|
|
2699
|
+
* Returns paginated entry points using the EntryPoint service defaults.
|
|
2700
|
+
* Existing request parameters can override those defaults.
|
|
1778
2701
|
* @public
|
|
1779
2702
|
*/
|
|
1780
2703
|
public async getEntryPoints(
|
|
@@ -1784,8 +2707,8 @@ export default class ContactCenter extends WebexPlugin implements IContactCenter
|
|
|
1784
2707
|
}
|
|
1785
2708
|
|
|
1786
2709
|
/**
|
|
1787
|
-
* Returns paginated contact service queues
|
|
1788
|
-
*
|
|
2710
|
+
* Returns paginated contact service queues using the Queue service defaults.
|
|
2711
|
+
* Existing request parameters can override those defaults.
|
|
1789
2712
|
* @public
|
|
1790
2713
|
*/
|
|
1791
2714
|
public async getQueues(
|