@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/dist/cc.js
CHANGED
|
@@ -19,12 +19,17 @@ var _Utils = require("./services/core/Utils");
|
|
|
19
19
|
var _types3 = require("./services/config/types");
|
|
20
20
|
var _TaskManager = _interopRequireDefault(require("./services/task/TaskManager"));
|
|
21
21
|
var _WebCallingService = _interopRequireDefault(require("./services/WebCallingService"));
|
|
22
|
+
var _AnswerCallOnWebexService = _interopRequireDefault(require("./services/AnswerCallOnWebexService"));
|
|
23
|
+
var _WebexCrossClientService = _interopRequireDefault(require("./services/WebexCrossClientService"));
|
|
24
|
+
var _WxAppTelephonyMercurySync = _interopRequireDefault(require("./services/WxAppTelephonyMercurySync"));
|
|
22
25
|
var _types4 = require("./services/task/types");
|
|
23
26
|
var _MetricsManager = _interopRequireDefault(require("./metrics/MetricsManager"));
|
|
24
27
|
var _constants4 = require("./metrics/constants");
|
|
25
|
-
var _EntryPoint =
|
|
26
|
-
var _AddressBook =
|
|
27
|
-
var _Queue =
|
|
28
|
+
var _EntryPoint = require("./services/EntryPoint");
|
|
29
|
+
var _AddressBook = require("./services/AddressBook");
|
|
30
|
+
var _Queue = require("./services/Queue");
|
|
31
|
+
var _ApiAiAssistant = require("./services/ApiAiAssistant");
|
|
32
|
+
var _UserPreference = require("./services/UserPreference");
|
|
28
33
|
function _interopRequireDefault(e) { return e && e.__esModule ? e : { default: e }; }
|
|
29
34
|
/**
|
|
30
35
|
* @module CCPlugin
|
|
@@ -84,6 +89,7 @@ function _interopRequireDefault(e) { return e && e.__esModule ? e : { default: e
|
|
|
84
89
|
* - `task:established` - Task/call has been connected
|
|
85
90
|
* - `task:ended` - Task/call has ended
|
|
86
91
|
* - `task:error` - An error occurred during task handling
|
|
92
|
+
* - `task:campaignPreviewReservation` - Campaign preview contact offered to agent
|
|
87
93
|
*
|
|
88
94
|
* @public
|
|
89
95
|
*
|
|
@@ -182,6 +188,29 @@ class ContactCenter extends _webexCore.WebexPlugin {
|
|
|
182
188
|
* @private
|
|
183
189
|
*/
|
|
184
190
|
|
|
191
|
+
/**
|
|
192
|
+
* REST telephony for wxApp thick-client answer (WXCC-6026)
|
|
193
|
+
* @private
|
|
194
|
+
*/
|
|
195
|
+
|
|
196
|
+
/**
|
|
197
|
+
* usersub cross-client state for Webex App toast suppression
|
|
198
|
+
* @private
|
|
199
|
+
*/
|
|
200
|
+
|
|
201
|
+
/**
|
|
202
|
+
* Mercury telephony mute sync for wxApp thick-client answer
|
|
203
|
+
* @private
|
|
204
|
+
*/
|
|
205
|
+
|
|
206
|
+
/** True when wxApp mute sync opened Mercury (Extension/DN-only profiles). */
|
|
207
|
+
wxAppMercuryConnectedByCc = false;
|
|
208
|
+
|
|
209
|
+
/** True when wxApp mute sync registered the Webex device. */
|
|
210
|
+
wxAppDeviceRegisteredByCc = false;
|
|
211
|
+
static WXAPP_FALSE_PUBLISH_RETRY_DELAY_MS = 30_000;
|
|
212
|
+
static WXAPP_FALSE_PUBLISH_MAX_RETRIES = 3;
|
|
213
|
+
|
|
185
214
|
/**
|
|
186
215
|
* Core service managers for Contact Center operations
|
|
187
216
|
* Includes agent, connection, and configuration services
|
|
@@ -272,6 +301,42 @@ class ContactCenter extends _webexCore.WebexPlugin {
|
|
|
272
301
|
* ```
|
|
273
302
|
*/
|
|
274
303
|
|
|
304
|
+
/**
|
|
305
|
+
* API instance for managing Webex Contact Center user preferences
|
|
306
|
+
* Provides functionality to get, create, update, and delete user preferences
|
|
307
|
+
* @type {UserPreference}
|
|
308
|
+
* @public
|
|
309
|
+
* @example
|
|
310
|
+
* ```typescript
|
|
311
|
+
* const cc = webex.cc;
|
|
312
|
+
* await cc.register();
|
|
313
|
+
* await cc.stationLogin({ teamId: 'team123', loginOption: 'BROWSER' });
|
|
314
|
+
*
|
|
315
|
+
* // Get user preferences for current user
|
|
316
|
+
* const preferences = await cc.userPreference.getUserPreference();
|
|
317
|
+
*
|
|
318
|
+
* // Create new user preferences
|
|
319
|
+
* const newPrefs = await cc.userPreference.createUserPreference({
|
|
320
|
+
* userId: 'user123',
|
|
321
|
+
* preferences: { e911Reminder: true }
|
|
322
|
+
* });
|
|
323
|
+
*
|
|
324
|
+
* // Update user preferences
|
|
325
|
+
* const updatedPrefs = await cc.userPreference.updateUserPreference('user123', {
|
|
326
|
+
* preferences: { e911Reminder: false }
|
|
327
|
+
* });
|
|
328
|
+
*
|
|
329
|
+
* // Delete user preferences
|
|
330
|
+
* await cc.userPreference.deleteUserPreference('user123');
|
|
331
|
+
* ```
|
|
332
|
+
*/
|
|
333
|
+
|
|
334
|
+
/**
|
|
335
|
+
* API instance for AI Assistant operations such as transcript controls.
|
|
336
|
+
* @type {ApiAIAssistant}
|
|
337
|
+
* @public
|
|
338
|
+
*/
|
|
339
|
+
|
|
275
340
|
/**
|
|
276
341
|
* Logger utility for Contact Center plugin
|
|
277
342
|
* Provides consistent logging across the plugin
|
|
@@ -293,6 +358,7 @@ class ContactCenter extends _webexCore.WebexPlugin {
|
|
|
293
358
|
this.$webex.once(_constants.READY, () => {
|
|
294
359
|
// @ts-ignore
|
|
295
360
|
this.$config = this.config;
|
|
361
|
+
this.validatePluginConfig();
|
|
296
362
|
|
|
297
363
|
/**
|
|
298
364
|
* This is used for handling the async requests by sending webex.request and wait for corresponding websocket event.
|
|
@@ -304,21 +370,24 @@ class ContactCenter extends _webexCore.WebexPlugin {
|
|
|
304
370
|
webex: this.$webex,
|
|
305
371
|
connectionConfig: this.getConnectionConfig()
|
|
306
372
|
});
|
|
307
|
-
this.services.webSocketManager.on('message', this.handleWebsocketMessage);
|
|
308
373
|
this.webCallingService = new _WebCallingService.default(this.$webex);
|
|
374
|
+
this.answerCallOnWebexService = new _AnswerCallOnWebexService.default(this.$webex);
|
|
375
|
+
this.webexCrossClientService = new _WebexCrossClientService.default(this.$webex);
|
|
376
|
+
this.wxAppTelephonyMercurySync = new _WxAppTelephonyMercurySync.default(this.$webex);
|
|
377
|
+
this.apiAIAssistant = new _ApiAiAssistant.ApiAIAssistant(this.$webex);
|
|
309
378
|
this.metricsManager = _MetricsManager.default.getInstance({
|
|
310
379
|
webex: this.$webex
|
|
311
380
|
});
|
|
312
|
-
this.taskManager = _TaskManager.default.getTaskManager(this.services.contact, this.webCallingService, this.services.webSocketManager);
|
|
381
|
+
this.taskManager = _TaskManager.default.getTaskManager(this.apiAIAssistant, this.services.contact, this.webCallingService, this.services.webSocketManager, this.services.rtdWebSocketManager);
|
|
382
|
+
this.taskManager.setAnswerCallOnWebexService(this.answerCallOnWebexService);
|
|
313
383
|
this.incomingTaskListener();
|
|
314
384
|
|
|
315
385
|
// Initialize API instances
|
|
316
386
|
// will have future function for indivdual fetch etc so better be in an object
|
|
317
|
-
this.entryPoint = new _EntryPoint.
|
|
318
|
-
this.addressBook = new _AddressBook.
|
|
319
|
-
this.queue = new _Queue.
|
|
320
|
-
|
|
321
|
-
// Initialize logger
|
|
387
|
+
this.entryPoint = new _EntryPoint.EntryPoint(this.$webex);
|
|
388
|
+
this.addressBook = new _AddressBook.AddressBook(this.$webex, () => this.agentConfig?.addressBookId);
|
|
389
|
+
this.queue = new _Queue.Queue(this.$webex);
|
|
390
|
+
this.userPreference = new _UserPreference.UserPreference(this.$webex, () => this.agentConfig?.agentId);
|
|
322
391
|
_loggerProxy.default.initialize(this.$webex.logger);
|
|
323
392
|
});
|
|
324
393
|
}
|
|
@@ -343,6 +412,16 @@ class ContactCenter extends _webexCore.WebexPlugin {
|
|
|
343
412
|
this.trigger(_types4.TASK_EVENTS.TASK_HYDRATE, task);
|
|
344
413
|
};
|
|
345
414
|
|
|
415
|
+
/**
|
|
416
|
+
* Handles multi-login hydrate events for SDK instances without Mobius registration
|
|
417
|
+
* @private
|
|
418
|
+
* @param {ITask} task The task object associated with the multi-login hydrate
|
|
419
|
+
*/
|
|
420
|
+
handleTaskMultiLoginHydrate = task => {
|
|
421
|
+
// @ts-ignore
|
|
422
|
+
this.trigger(_types4.TASK_EVENTS.TASK_MULTI_LOGIN_HYDRATE, task);
|
|
423
|
+
};
|
|
424
|
+
|
|
346
425
|
/**
|
|
347
426
|
* Handles task merged events when tasks are combined eg: EPDN merge/transfer
|
|
348
427
|
* @private
|
|
@@ -353,6 +432,19 @@ class ContactCenter extends _webexCore.WebexPlugin {
|
|
|
353
432
|
this.trigger(_types4.TASK_EVENTS.TASK_MERGED, task);
|
|
354
433
|
};
|
|
355
434
|
|
|
435
|
+
/**
|
|
436
|
+
* Handles campaign preview reservation events when a contact is offered to the agent
|
|
437
|
+
* @private
|
|
438
|
+
* @param {ITask} task The campaign reservation task
|
|
439
|
+
*/
|
|
440
|
+
handleCampaignPreviewReservation = task => {
|
|
441
|
+
// @ts-ignore
|
|
442
|
+
this.trigger(_types4.TASK_EVENTS.TASK_CAMPAIGN_PREVIEW_RESERVATION, task);
|
|
443
|
+
};
|
|
444
|
+
handleRTDWebsocketMessage = event => {
|
|
445
|
+
this.taskManager.handleRealtimeWebsocketEvent(event);
|
|
446
|
+
};
|
|
447
|
+
|
|
356
448
|
/**
|
|
357
449
|
* Sets up event listeners for incoming tasks and task hydration
|
|
358
450
|
* Subscribes to task events from the task manager
|
|
@@ -361,7 +453,9 @@ class ContactCenter extends _webexCore.WebexPlugin {
|
|
|
361
453
|
incomingTaskListener() {
|
|
362
454
|
this.taskManager.on(_types4.TASK_EVENTS.TASK_INCOMING, this.handleIncomingTask);
|
|
363
455
|
this.taskManager.on(_types4.TASK_EVENTS.TASK_HYDRATE, this.handleTaskHydrate);
|
|
456
|
+
this.taskManager.on(_types4.TASK_EVENTS.TASK_MULTI_LOGIN_HYDRATE, this.handleTaskMultiLoginHydrate);
|
|
364
457
|
this.taskManager.on(_types4.TASK_EVENTS.TASK_MERGED, this.handleTaskMerged);
|
|
458
|
+
this.taskManager.on(_types4.TASK_EVENTS.TASK_CAMPAIGN_PREVIEW_RESERVATION, this.handleCampaignPreviewReservation);
|
|
365
459
|
}
|
|
366
460
|
|
|
367
461
|
/**
|
|
@@ -401,13 +495,14 @@ class ContactCenter extends _webexCore.WebexPlugin {
|
|
|
401
495
|
* ```
|
|
402
496
|
*/
|
|
403
497
|
async register() {
|
|
404
|
-
_loggerProxy.default.
|
|
498
|
+
_loggerProxy.default.log('Starting CC SDK registration', {
|
|
405
499
|
module: _constants.CC_FILE,
|
|
406
500
|
method: _constants.METHODS.REGISTER
|
|
407
501
|
});
|
|
408
502
|
try {
|
|
409
503
|
this.metricsManager.timeEvent([_constants4.METRIC_EVENT_NAMES.WEBSOCKET_REGISTER_SUCCESS, _constants4.METRIC_EVENT_NAMES.WEBSOCKET_REGISTER_FAILED]);
|
|
410
504
|
this.setupEventListeners();
|
|
505
|
+
this.services.webSocketManager.on('message', this.handleWebsocketMessage);
|
|
411
506
|
const resp = await this.connectWebsocket();
|
|
412
507
|
// Ensure 'dn' is always populated from 'defaultDn'
|
|
413
508
|
resp.dn = resp.defaultDn;
|
|
@@ -470,9 +565,17 @@ class ContactCenter extends _webexCore.WebexPlugin {
|
|
|
470
565
|
this.metricsManager.timeEvent([_constants4.METRIC_EVENT_NAMES.WEBSOCKET_DEREGISTER_SUCCESS, _constants4.METRIC_EVENT_NAMES.WEBSOCKET_DEREGISTER_FAIL]);
|
|
471
566
|
this.taskManager.off(_types4.TASK_EVENTS.TASK_INCOMING, this.handleIncomingTask);
|
|
472
567
|
this.taskManager.off(_types4.TASK_EVENTS.TASK_HYDRATE, this.handleTaskHydrate);
|
|
568
|
+
this.taskManager.off(_types4.TASK_EVENTS.TASK_MULTI_LOGIN_HYDRATE, this.handleTaskMultiLoginHydrate);
|
|
569
|
+
this.taskManager.off(_types4.TASK_EVENTS.TASK_CAMPAIGN_PREVIEW_RESERVATION, this.handleCampaignPreviewReservation);
|
|
473
570
|
this.taskManager.unregisterIncomingCallEvent();
|
|
474
571
|
this.services.webSocketManager.off('message', this.handleWebsocketMessage);
|
|
572
|
+
this.services.rtdWebSocketManager.off('message', this.handleRTDWebsocketMessage);
|
|
475
573
|
this.services.connectionService.off('connectionLost', this.handleConnectionLost);
|
|
574
|
+
const {
|
|
575
|
+
publishError: wxAppPublishError
|
|
576
|
+
} = await this.teardownWxAppLocalState({
|
|
577
|
+
clearInitFlag: true
|
|
578
|
+
});
|
|
476
579
|
if (this.agentConfig.webRtcEnabled && this.agentConfig.loginVoiceOptions.includes(_types.LoginOption.BROWSER)) {
|
|
477
580
|
if (this.$webex.internal.mercury.connected) {
|
|
478
581
|
this.$webex.internal.mercury.off('online');
|
|
@@ -489,9 +592,18 @@ class ContactCenter extends _webexCore.WebexPlugin {
|
|
|
489
592
|
if (!this.services.webSocketManager.isSocketClosed) {
|
|
490
593
|
this.services.webSocketManager.close(false, 'Unregistering the SDK');
|
|
491
594
|
}
|
|
595
|
+
if (this.services.rtdWebSocketManager && !this.services.rtdWebSocketManager.isSocketClosed) {
|
|
596
|
+
this.services.rtdWebSocketManager.close(false, 'Unregistering the SDK');
|
|
597
|
+
}
|
|
598
|
+
if (this.services.rtdWebSocketManager && !this.services.rtdWebSocketManager.isSocketClosed) {
|
|
599
|
+
this.services.rtdWebSocketManager.close(false, 'Unregistering the RTD websocket');
|
|
600
|
+
}
|
|
492
601
|
|
|
493
602
|
// Clear any cached agent configuration
|
|
494
603
|
this.agentConfig = null;
|
|
604
|
+
if (wxAppPublishError) {
|
|
605
|
+
throw wxAppPublishError;
|
|
606
|
+
}
|
|
495
607
|
_loggerProxy.default.log('Deregistered successfully', {
|
|
496
608
|
module: _constants.CC_FILE,
|
|
497
609
|
method: _constants.METHODS.DEREGISTER
|
|
@@ -545,6 +657,12 @@ class ContactCenter extends _webexCore.WebexPlugin {
|
|
|
545
657
|
* ```
|
|
546
658
|
*/
|
|
547
659
|
async getBuddyAgents(data) {
|
|
660
|
+
const {
|
|
661
|
+
action,
|
|
662
|
+
state,
|
|
663
|
+
mediaType = 'telephony'
|
|
664
|
+
} = data;
|
|
665
|
+
const buddyAgentState = state ?? (action === 'Transfer' ? _constants2.AGENT_STATE_AVAILABLE : undefined);
|
|
548
666
|
_loggerProxy.default.info('Fetching buddy agents', {
|
|
549
667
|
module: _constants.CC_FILE,
|
|
550
668
|
method: _constants.METHODS.GET_BUDDY_AGENTS
|
|
@@ -554,13 +672,16 @@ class ContactCenter extends _webexCore.WebexPlugin {
|
|
|
554
672
|
const resp = await this.services.agent.buddyAgents({
|
|
555
673
|
data: {
|
|
556
674
|
agentProfileId: this.agentConfig.agentProfileID,
|
|
557
|
-
|
|
675
|
+
mediaType,
|
|
676
|
+
...(buddyAgentState ? {
|
|
677
|
+
state: buddyAgentState
|
|
678
|
+
} : {})
|
|
558
679
|
}
|
|
559
680
|
});
|
|
560
681
|
this.metricsManager.trackEvent(_constants4.METRIC_EVENT_NAMES.FETCH_BUDDY_AGENTS_SUCCESS, {
|
|
561
682
|
..._MetricsManager.default.getCommonTrackingFieldForAQMResponse(resp),
|
|
562
|
-
mediaType
|
|
563
|
-
buddyAgentState
|
|
683
|
+
mediaType,
|
|
684
|
+
buddyAgentState,
|
|
564
685
|
buddyAgentCount: resp.data.agentList.length
|
|
565
686
|
}, ['operational']);
|
|
566
687
|
_loggerProxy.default.log(`Successfully retrieved ${resp.data.agentList.length} buddy agents`, {
|
|
@@ -573,8 +694,8 @@ class ContactCenter extends _webexCore.WebexPlugin {
|
|
|
573
694
|
const failureResp = error.details;
|
|
574
695
|
this.metricsManager.trackEvent(_constants4.METRIC_EVENT_NAMES.FETCH_BUDDY_AGENTS_FAILED, {
|
|
575
696
|
..._MetricsManager.default.getCommonTrackingFieldForAQMResponseFailed(failureResp),
|
|
576
|
-
mediaType
|
|
577
|
-
buddyAgentState
|
|
697
|
+
mediaType,
|
|
698
|
+
buddyAgentState
|
|
578
699
|
}, ['operational']);
|
|
579
700
|
const {
|
|
580
701
|
error: detailedError
|
|
@@ -590,13 +711,14 @@ class ContactCenter extends _webexCore.WebexPlugin {
|
|
|
590
711
|
* @private
|
|
591
712
|
*/
|
|
592
713
|
async connectWebsocket() {
|
|
593
|
-
_loggerProxy.default.
|
|
714
|
+
_loggerProxy.default.log('Connecting to websocket', {
|
|
594
715
|
module: _constants.CC_FILE,
|
|
595
716
|
method: _constants.METHODS.CONNECT_WEBSOCKET
|
|
596
717
|
});
|
|
597
718
|
try {
|
|
598
719
|
const data = await this.services.webSocketManager.initWebSocket({
|
|
599
|
-
body: this.getConnectionConfig()
|
|
720
|
+
body: this.getConnectionConfig(),
|
|
721
|
+
resource: _constants3.SUBSCRIBE_API
|
|
600
722
|
});
|
|
601
723
|
const agentId = data.agentId;
|
|
602
724
|
const orgId = this.$webex.credentials.getOrgId();
|
|
@@ -605,12 +727,53 @@ class ContactCenter extends _webexCore.WebexPlugin {
|
|
|
605
727
|
module: _constants.CC_FILE,
|
|
606
728
|
method: _constants.METHODS.CONNECT_WEBSOCKET
|
|
607
729
|
});
|
|
608
|
-
|
|
730
|
+
const configFlags = {
|
|
731
|
+
isEndTaskEnabled: this.agentConfig.isEndTaskEnabled,
|
|
732
|
+
isEndConsultEnabled: this.agentConfig.isEndConsultEnabled,
|
|
733
|
+
webRtcEnabled: this.agentConfig.webRtcEnabled,
|
|
734
|
+
autoWrapup: this.agentConfig.wrapUpData?.wrapUpProps?.autoWrapup ?? false,
|
|
735
|
+
aiFeature: this.agentConfig.aiFeature,
|
|
736
|
+
consultTransfer: {
|
|
737
|
+
allowConsultToQueue: this.agentConfig.allowConsultToQueue,
|
|
738
|
+
accessQueue: this.agentConfig.accessQueue,
|
|
739
|
+
accessEntryPoint: this.agentConfig.accessEntryPoint,
|
|
740
|
+
accessBuddyTeam: this.agentConfig.accessBuddyTeam
|
|
741
|
+
},
|
|
742
|
+
enableWxBetterTogether: this.isWxBetterTogetherEnabled()
|
|
743
|
+
};
|
|
744
|
+
this.taskManager.setConfigFlags(configFlags);
|
|
609
745
|
// TODO: Make profile a singleton to make it available throughout app/sdk so we dont need to inject info everywhere
|
|
610
746
|
this.taskManager.setWrapupData(this.agentConfig.wrapUpData);
|
|
611
747
|
this.taskManager.setAgentId(this.agentConfig.agentId);
|
|
612
748
|
this.taskManager.setWebRtcEnabled(this.agentConfig.webRtcEnabled);
|
|
613
|
-
|
|
749
|
+
this.apiAIAssistant.setAIFeatureFlags(this.agentConfig.aiFeature);
|
|
750
|
+
|
|
751
|
+
/**
|
|
752
|
+
* RTD websocket currently supports realtime transcripts and suggested responses.
|
|
753
|
+
* Extend this condition when additional AI RTD features are introduced.
|
|
754
|
+
*/
|
|
755
|
+
if (this.agentConfig.aiFeature?.realtimeTranscripts?.enable || this.agentConfig.aiFeature?.suggestedResponses?.enable) {
|
|
756
|
+
_loggerProxy.default.info('Connecting to RTD websocket', {
|
|
757
|
+
module: _constants.CC_FILE,
|
|
758
|
+
method: _constants.METHODS.CONNECT_WEBSOCKET
|
|
759
|
+
});
|
|
760
|
+
this.services.rtdWebSocketManager.initWebSocket({
|
|
761
|
+
body: this.getConnectionConfig(),
|
|
762
|
+
resource: _constants3.RTD_SUBSCRIBE_API
|
|
763
|
+
}).then(() => {
|
|
764
|
+
_loggerProxy.default.log('RTD websocket connected successfully', {
|
|
765
|
+
module: _constants.CC_FILE,
|
|
766
|
+
method: _constants.METHODS.CONNECT_WEBSOCKET
|
|
767
|
+
});
|
|
768
|
+
this.services.rtdWebSocketManager.on('message', this.handleRTDWebsocketMessage);
|
|
769
|
+
}).catch(error => {
|
|
770
|
+
_loggerProxy.default.error(`Error connecting to RTD websocket ${error}`, {
|
|
771
|
+
module: _constants.CC_FILE,
|
|
772
|
+
method: _constants.METHODS.CONNECT_WEBSOCKET
|
|
773
|
+
});
|
|
774
|
+
});
|
|
775
|
+
}
|
|
776
|
+
if (this.agentConfig.webRtcEnabled && this.agentConfig.loginVoiceOptions.includes(_types.LoginOption.BROWSER) && !this.isWebRTCRegistrationDisabled()) {
|
|
614
777
|
try {
|
|
615
778
|
await this.$webex.internal.mercury.connect();
|
|
616
779
|
_loggerProxy.default.log('Authentication: webex.internal.mercury.connect successful', {
|
|
@@ -623,9 +786,19 @@ class ContactCenter extends _webexCore.WebexPlugin {
|
|
|
623
786
|
method: _constants.METHODS.CONNECT_WEBSOCKET
|
|
624
787
|
});
|
|
625
788
|
}
|
|
789
|
+
} else if (this.isWebRTCRegistrationDisabled()) {
|
|
790
|
+
_loggerProxy.default.info('Skipping Mobius registration because disableWebRTCRegistration is enabled', {
|
|
791
|
+
module: _constants.CC_FILE,
|
|
792
|
+
method: _constants.METHODS.CONNECT_WEBSOCKET
|
|
793
|
+
});
|
|
626
794
|
}
|
|
627
795
|
if (this.$config && this.$config.allowAutomatedRelogin) {
|
|
628
796
|
await this.silentRelogin();
|
|
797
|
+
} else {
|
|
798
|
+
_loggerProxy.default.log('Skipping silent relogin: allowAutomatedRelogin is disabled', {
|
|
799
|
+
module: _constants.CC_FILE,
|
|
800
|
+
method: _constants.METHODS.CONNECT_WEBSOCKET
|
|
801
|
+
});
|
|
629
802
|
}
|
|
630
803
|
return this.agentConfig;
|
|
631
804
|
} catch (error) {
|
|
@@ -666,21 +839,27 @@ class ContactCenter extends _webexCore.WebexPlugin {
|
|
|
666
839
|
* ```
|
|
667
840
|
*/
|
|
668
841
|
async stationLogin(data) {
|
|
669
|
-
|
|
842
|
+
const loggerContext = {
|
|
670
843
|
module: _constants.CC_FILE,
|
|
671
844
|
method: _constants.METHODS.STATION_LOGIN
|
|
672
|
-
}
|
|
845
|
+
};
|
|
673
846
|
try {
|
|
847
|
+
_loggerProxy.default.log(`Starting agent station login | loginOption: ${data?.loginOption} teamId: ${data?.teamId}`, loggerContext);
|
|
674
848
|
this.metricsManager.timeEvent([_constants4.METRIC_EVENT_NAMES.STATION_LOGIN_SUCCESS, _constants4.METRIC_EVENT_NAMES.STATION_LOGIN_FAILED]);
|
|
675
|
-
|
|
676
|
-
|
|
677
|
-
|
|
678
|
-
|
|
679
|
-
data: {
|
|
680
|
-
|
|
681
|
-
|
|
682
|
-
|
|
683
|
-
|
|
849
|
+
const dialPlanEntries = this.agentConfig?.dialPlan?.dialPlanEntity ?? [];
|
|
850
|
+
if (data.loginOption === _types.LoginOption.AGENT_DN) {
|
|
851
|
+
_loggerProxy.default.log(`Validating dial number | dialPlanEnabled: ${!!this.agentConfig?.dialPlan} | dialPlanEntryCount: ${dialPlanEntries.length}`, loggerContext);
|
|
852
|
+
if (!(0, _Utils.isValidDialNumber)(data.dialNumber, dialPlanEntries)) {
|
|
853
|
+
_loggerProxy.default.log(`Dial number validation failed | dialNumber: ${data.dialNumber} | dialPlanEntryCount: ${dialPlanEntries.length}`, loggerContext);
|
|
854
|
+
const error = new Error('INVALID_DIAL_NUMBER');
|
|
855
|
+
// @ts-ignore - adding custom key to the error object
|
|
856
|
+
error.details = {
|
|
857
|
+
data: {
|
|
858
|
+
reason: 'INVALID_DIAL_NUMBER'
|
|
859
|
+
}
|
|
860
|
+
};
|
|
861
|
+
throw error;
|
|
862
|
+
}
|
|
684
863
|
}
|
|
685
864
|
const loginResponse = await this.services.agent.stationLogin({
|
|
686
865
|
data: {
|
|
@@ -696,8 +875,13 @@ class ContactCenter extends _webexCore.WebexPlugin {
|
|
|
696
875
|
auxCodeId: _constants.EMPTY_STRING
|
|
697
876
|
}
|
|
698
877
|
});
|
|
699
|
-
if (this.agentConfig.webRtcEnabled && data.loginOption === _types.LoginOption.BROWSER) {
|
|
878
|
+
if (this.agentConfig.webRtcEnabled && data.loginOption === _types.LoginOption.BROWSER && !this.isWebRTCRegistrationDisabled()) {
|
|
700
879
|
await this.webCallingService.registerWebCallingLine();
|
|
880
|
+
} else if (this.agentConfig.webRtcEnabled && data.loginOption === _types.LoginOption.BROWSER && this.isWebRTCRegistrationDisabled()) {
|
|
881
|
+
_loggerProxy.default.info('Skipping web calling line registration because disableWebRTCRegistration is enabled', {
|
|
882
|
+
module: _constants.CC_FILE,
|
|
883
|
+
method: _constants.METHODS.STATION_LOGIN
|
|
884
|
+
});
|
|
701
885
|
}
|
|
702
886
|
const resp = await loginResponse;
|
|
703
887
|
const {
|
|
@@ -716,6 +900,13 @@ class ContactCenter extends _webexCore.WebexPlugin {
|
|
|
716
900
|
notifsTrackingId: resp.trackingId
|
|
717
901
|
};
|
|
718
902
|
this.webCallingService.setLoginOption(data.loginOption);
|
|
903
|
+
if (this.agentConfig) {
|
|
904
|
+
this.agentConfig.deviceType = data.loginOption;
|
|
905
|
+
if (data.loginOption === _types.LoginOption.AGENT_DN || data.loginOption === _types.LoginOption.EXTENSION) {
|
|
906
|
+
this.agentConfig.defaultDn = data.dialNumber;
|
|
907
|
+
this.agentConfig.dn = data.dialNumber;
|
|
908
|
+
}
|
|
909
|
+
}
|
|
719
910
|
this.metricsManager.trackEvent(_constants4.METRIC_EVENT_NAMES.STATION_LOGIN_SUCCESS, {
|
|
720
911
|
..._MetricsManager.default.getCommonTrackingFieldForAQMResponse(resp),
|
|
721
912
|
loginType: data.loginOption,
|
|
@@ -728,6 +919,7 @@ class ContactCenter extends _webexCore.WebexPlugin {
|
|
|
728
919
|
method: _constants.METHODS.STATION_LOGIN,
|
|
729
920
|
trackingId: resp.trackingId
|
|
730
921
|
});
|
|
922
|
+
await this.ensureWxAppPostStationLogin();
|
|
731
923
|
return response;
|
|
732
924
|
} catch (error) {
|
|
733
925
|
const failure = error.details;
|
|
@@ -782,6 +974,7 @@ class ContactCenter extends _webexCore.WebexPlugin {
|
|
|
782
974
|
if (this.webCallingService) {
|
|
783
975
|
this.webCallingService.deregisterWebCallingLine();
|
|
784
976
|
}
|
|
977
|
+
await this.teardownWxAppLocalState();
|
|
785
978
|
_loggerProxy.default.log(`Agent station logout completed successfully`, {
|
|
786
979
|
module: _constants.CC_FILE,
|
|
787
980
|
method: _constants.METHODS.STATION_LOGOUT,
|
|
@@ -1021,6 +1214,391 @@ class ContactCenter extends _webexCore.WebexPlugin {
|
|
|
1021
1214
|
}
|
|
1022
1215
|
};
|
|
1023
1216
|
|
|
1217
|
+
/**
|
|
1218
|
+
* Checks whether Mobius/WebRTC registration should be skipped by config
|
|
1219
|
+
* @returns {boolean} True when browser WebRTC registration is disabled
|
|
1220
|
+
* @private
|
|
1221
|
+
*/
|
|
1222
|
+
isWebRTCRegistrationDisabled() {
|
|
1223
|
+
return this.$config?.disableWebRTCRegistration === true;
|
|
1224
|
+
}
|
|
1225
|
+
|
|
1226
|
+
/**
|
|
1227
|
+
* Validates contact-center plugin configuration before service initialization
|
|
1228
|
+
* @private
|
|
1229
|
+
*/
|
|
1230
|
+
validatePluginConfig() {
|
|
1231
|
+
if (this.$config?.disableWebRTCRegistration === true && this.$config?.allowMultiLogin === false) {
|
|
1232
|
+
throw new Error('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.');
|
|
1233
|
+
}
|
|
1234
|
+
}
|
|
1235
|
+
|
|
1236
|
+
/**
|
|
1237
|
+
* Whether wxApp thick-client answer is enabled for this SDK instance.
|
|
1238
|
+
* @public
|
|
1239
|
+
*/
|
|
1240
|
+
isWxBetterTogetherEnabled() {
|
|
1241
|
+
return this.$config?.enableWxBetterTogether === true;
|
|
1242
|
+
}
|
|
1243
|
+
|
|
1244
|
+
/**
|
|
1245
|
+
* Current station login option (Extension, Dial Number, or Browser/Desktop).
|
|
1246
|
+
* Prefer webCallingService — updated on every stationLogin before wxApp hooks run.
|
|
1247
|
+
* @private
|
|
1248
|
+
*/
|
|
1249
|
+
getCurrentStationLoginOption() {
|
|
1250
|
+
return this.webCallingService?.loginOption ?? this.agentConfig?.deviceType;
|
|
1251
|
+
}
|
|
1252
|
+
|
|
1253
|
+
/**
|
|
1254
|
+
* wxApp thick-client answer is supported for Extension and Dial Number station login only —
|
|
1255
|
+
* not Browser/Desktop (WebRTC) login.
|
|
1256
|
+
* @private
|
|
1257
|
+
*/
|
|
1258
|
+
assertWxAppStationLoginSupportedForEnable() {
|
|
1259
|
+
const loginOption = this.getCurrentStationLoginOption();
|
|
1260
|
+
if (loginOption !== _types.LoginOption.EXTENSION && loginOption !== _types.LoginOption.AGENT_DN) {
|
|
1261
|
+
throw new Error('setManageWebexCallingInWxcc requires EXTENSION or AGENT_DN station login. Complete station login before enabling.');
|
|
1262
|
+
}
|
|
1263
|
+
}
|
|
1264
|
+
|
|
1265
|
+
/**
|
|
1266
|
+
* Clears runtime wxApp config after logout/deregister so stale flags do not apply on relogin.
|
|
1267
|
+
* @private
|
|
1268
|
+
*/
|
|
1269
|
+
resetEnableWxBetterTogetherConfig() {
|
|
1270
|
+
if (this.$config) {
|
|
1271
|
+
this.$config.enableWxBetterTogether = false;
|
|
1272
|
+
}
|
|
1273
|
+
this.taskManager.applyEnableWxBetterTogether(false);
|
|
1274
|
+
}
|
|
1275
|
+
|
|
1276
|
+
/**
|
|
1277
|
+
* Runtime enable/disable for wxApp Better Together (toast suppression + Mercury mute sync).
|
|
1278
|
+
*
|
|
1279
|
+
* **Phase 1 (WXCC-6026 / MMT): NOT part of the public host contract.**
|
|
1280
|
+
* Hosts must set `webexConfig.cc.enableWxBetterTogether` before `webex.init()` / `cc.register()`.
|
|
1281
|
+
* To change the flag after the SDK is initialized, re-init the SDK with the updated config.
|
|
1282
|
+
*
|
|
1283
|
+
* **Supported public read API:** {@link isWxBetterTogetherEnabled}.
|
|
1284
|
+
* **Supported telephony API:** unified `task.accept()`, `task.decline()`, `task.toggleMute()`,
|
|
1285
|
+
* `task.transmitDtmf()` — SDK routes wxApp calls internally when the init flag is active.
|
|
1286
|
+
*
|
|
1287
|
+
* **Production lifecycle does not call this method.** Station login, silent relogin, logout,
|
|
1288
|
+
* and deregister use {@link ensureWxAppPostStationLogin} and {@link teardownWxAppLocalState}
|
|
1289
|
+
* (usersub publish + Mercury subscribe/unsubscribe based on the init flag).
|
|
1290
|
+
*
|
|
1291
|
+
* This setter remains as a **private implementation** for Phase 2 runtime toggle and unit tests.
|
|
1292
|
+
* It updates `$config.enableWxBetterTogether`, TaskManager flags, cross-client usersub
|
|
1293
|
+
* (`answer-calls-on-wxcc`), and Mercury mute sync; rolls back config on publish/connect failure.
|
|
1294
|
+
*
|
|
1295
|
+
* @param enabled - `true` to enable wxApp answer + usersub suppression; `false` to disable and tear down.
|
|
1296
|
+
* @throws When enabling without login, on unsupported BROWSER station login, or when usersub/Mercury init fails.
|
|
1297
|
+
* @internal
|
|
1298
|
+
* @see enableWxBetterTogether (CCPluginConfig init flag)
|
|
1299
|
+
* @see ensureWxAppPostStationLogin
|
|
1300
|
+
* @see teardownWxAppLocalState
|
|
1301
|
+
*/
|
|
1302
|
+
async setManageWebexCallingInWxcc(enabled) {
|
|
1303
|
+
if (enabled && !this.$webex.internal.device?.userId) {
|
|
1304
|
+
throw new Error('Cannot publish answer-calls-on-wxcc: user is not logged in');
|
|
1305
|
+
}
|
|
1306
|
+
if (enabled) {
|
|
1307
|
+
this.assertWxAppStationLoginSupportedForEnable();
|
|
1308
|
+
}
|
|
1309
|
+
const previousEnabled = this.isWxBetterTogetherEnabled();
|
|
1310
|
+
if (this.$config) {
|
|
1311
|
+
this.$config.enableWxBetterTogether = enabled;
|
|
1312
|
+
}
|
|
1313
|
+
this.taskManager.applyEnableWxBetterTogether(enabled);
|
|
1314
|
+
let publishedEnable = false;
|
|
1315
|
+
try {
|
|
1316
|
+
if (enabled) {
|
|
1317
|
+
await this.ensureWxAppMercuryAndSubscribe();
|
|
1318
|
+
await this.publishAnswerOnWebexCrossClientState(true);
|
|
1319
|
+
publishedEnable = true;
|
|
1320
|
+
this.taskManager.syncWxAppMuteFromCallDetailsForAllTasks();
|
|
1321
|
+
} else {
|
|
1322
|
+
await this.publishAnswerOnWebexCrossClientState(false);
|
|
1323
|
+
this.wxAppTelephonyMercurySync.unsubscribe();
|
|
1324
|
+
await this.releaseWxAppMercuryResources();
|
|
1325
|
+
}
|
|
1326
|
+
} catch (error) {
|
|
1327
|
+
if (publishedEnable) {
|
|
1328
|
+
await this.revertWxAppCrossClientPublish();
|
|
1329
|
+
} else if (enabled) {
|
|
1330
|
+
this.wxAppTelephonyMercurySync.unsubscribe();
|
|
1331
|
+
await this.releaseWxAppMercuryResources();
|
|
1332
|
+
}
|
|
1333
|
+
if (this.$config) {
|
|
1334
|
+
this.$config.enableWxBetterTogether = previousEnabled;
|
|
1335
|
+
}
|
|
1336
|
+
this.taskManager.applyEnableWxBetterTogether(previousEnabled);
|
|
1337
|
+
throw error;
|
|
1338
|
+
}
|
|
1339
|
+
}
|
|
1340
|
+
async ensureWxAppPostStationLogin() {
|
|
1341
|
+
if (this.getCurrentStationLoginOption() === _types.LoginOption.BROWSER) {
|
|
1342
|
+
return;
|
|
1343
|
+
}
|
|
1344
|
+
let publishedEnable = false;
|
|
1345
|
+
try {
|
|
1346
|
+
if (this.isWxBetterTogetherEnabled()) {
|
|
1347
|
+
await this.ensureWxAppMercuryAndSubscribe();
|
|
1348
|
+
await this.publishAnswerOnWebexCrossClientState(true);
|
|
1349
|
+
publishedEnable = true;
|
|
1350
|
+
this.taskManager.syncWxAppMuteFromCallDetailsForAllTasks();
|
|
1351
|
+
} else {
|
|
1352
|
+
await this.ensureWxAppDeviceRegistered();
|
|
1353
|
+
await this.publishAnswerOnWebexCrossClientState(false, {
|
|
1354
|
+
force: true
|
|
1355
|
+
});
|
|
1356
|
+
this.webexCrossClientService.teardown();
|
|
1357
|
+
this.wxAppTelephonyMercurySync.unsubscribe();
|
|
1358
|
+
await this.releaseWxAppMercuryResources();
|
|
1359
|
+
}
|
|
1360
|
+
} catch (error) {
|
|
1361
|
+
_loggerProxy.default.error(`Failed to initialize wxApp post-station-login: ${error}`, {
|
|
1362
|
+
module: _constants.CC_FILE,
|
|
1363
|
+
method: _constants.METHODS.STATION_LOGIN
|
|
1364
|
+
});
|
|
1365
|
+
if (this.isWxBetterTogetherEnabled()) {
|
|
1366
|
+
if (publishedEnable) {
|
|
1367
|
+
await this.revertWxAppCrossClientPublish();
|
|
1368
|
+
} else {
|
|
1369
|
+
this.wxAppTelephonyMercurySync.unsubscribe();
|
|
1370
|
+
await this.releaseWxAppMercuryResources();
|
|
1371
|
+
}
|
|
1372
|
+
this.resetEnableWxBetterTogetherConfig();
|
|
1373
|
+
} else {
|
|
1374
|
+
this.scheduleForcedFalsePublishRetry();
|
|
1375
|
+
}
|
|
1376
|
+
}
|
|
1377
|
+
}
|
|
1378
|
+
clearWxAppFalsePublishRetryTimer() {
|
|
1379
|
+
if (this.wxAppFalsePublishRetryTimer) {
|
|
1380
|
+
clearTimeout(this.wxAppFalsePublishRetryTimer);
|
|
1381
|
+
this.wxAppFalsePublishRetryTimer = undefined;
|
|
1382
|
+
}
|
|
1383
|
+
}
|
|
1384
|
+
scheduleForcedFalsePublishRetry(retryAttempt = 0) {
|
|
1385
|
+
this.scheduleFalsePublishRetry(retryAttempt, {
|
|
1386
|
+
requireDisabled: true
|
|
1387
|
+
});
|
|
1388
|
+
}
|
|
1389
|
+
|
|
1390
|
+
/**
|
|
1391
|
+
* Retries compensating false publish after rollback failure, regardless of enabled flag.
|
|
1392
|
+
* @private
|
|
1393
|
+
*/
|
|
1394
|
+
scheduleCompensatingFalsePublishRetry(retryAttempt = 0) {
|
|
1395
|
+
this.scheduleFalsePublishRetry(retryAttempt);
|
|
1396
|
+
}
|
|
1397
|
+
scheduleFalsePublishRetry(retryAttempt = 0, options = {}) {
|
|
1398
|
+
if (retryAttempt >= ContactCenter.WXAPP_FALSE_PUBLISH_MAX_RETRIES) {
|
|
1399
|
+
return;
|
|
1400
|
+
}
|
|
1401
|
+
if (options?.requireDisabled && this.isWxBetterTogetherEnabled()) {
|
|
1402
|
+
return;
|
|
1403
|
+
}
|
|
1404
|
+
this.clearWxAppFalsePublishRetryTimer();
|
|
1405
|
+
this.wxAppFalsePublishRetryTimer = setTimeout(async () => {
|
|
1406
|
+
this.wxAppFalsePublishRetryTimer = undefined;
|
|
1407
|
+
if (options?.requireDisabled && this.isWxBetterTogetherEnabled()) {
|
|
1408
|
+
return;
|
|
1409
|
+
}
|
|
1410
|
+
if (!options?.requireDisabled && this.isWxBetterTogetherEnabled() && this.webexCrossClientService.isAnswerCallsStateActive()) {
|
|
1411
|
+
return;
|
|
1412
|
+
}
|
|
1413
|
+
try {
|
|
1414
|
+
await this.ensureWxAppDeviceRegistered();
|
|
1415
|
+
await this.publishAnswerOnWebexCrossClientState(false, {
|
|
1416
|
+
force: true
|
|
1417
|
+
});
|
|
1418
|
+
this.webexCrossClientService.teardown();
|
|
1419
|
+
this.wxAppTelephonyMercurySync.unsubscribe();
|
|
1420
|
+
await this.releaseWxAppMercuryResources();
|
|
1421
|
+
} catch (retryError) {
|
|
1422
|
+
_loggerProxy.default.error(`Failed to retry forced answer-calls-on-wxcc false publish: ${retryError}`, {
|
|
1423
|
+
module: _constants.CC_FILE,
|
|
1424
|
+
method: _constants.METHODS.SET_MANAGE_WEBEX_CALLING_IN_WXCC
|
|
1425
|
+
});
|
|
1426
|
+
this.scheduleFalsePublishRetry(retryAttempt + 1, options);
|
|
1427
|
+
}
|
|
1428
|
+
}, ContactCenter.WXAPP_FALSE_PUBLISH_RETRY_DELAY_MS);
|
|
1429
|
+
}
|
|
1430
|
+
|
|
1431
|
+
/**
|
|
1432
|
+
* Best-effort rollback when usersub true was published but wxApp setup did not complete.
|
|
1433
|
+
* @private
|
|
1434
|
+
*/
|
|
1435
|
+
async revertWxAppCrossClientPublish() {
|
|
1436
|
+
try {
|
|
1437
|
+
await this.publishAnswerOnWebexCrossClientState(false, {
|
|
1438
|
+
force: true
|
|
1439
|
+
});
|
|
1440
|
+
} catch (error) {
|
|
1441
|
+
_loggerProxy.default.error(`Failed to publish compensating answer-calls-on-wxcc false during wxApp rollback: ${error}`, {
|
|
1442
|
+
module: _constants.CC_FILE,
|
|
1443
|
+
method: _constants.METHODS.SET_MANAGE_WEBEX_CALLING_IN_WXCC
|
|
1444
|
+
});
|
|
1445
|
+
this.scheduleCompensatingFalsePublishRetry();
|
|
1446
|
+
}
|
|
1447
|
+
this.webexCrossClientService.teardown();
|
|
1448
|
+
this.wxAppTelephonyMercurySync.unsubscribe();
|
|
1449
|
+
await this.releaseWxAppMercuryResources();
|
|
1450
|
+
}
|
|
1451
|
+
async ensureWxAppDeviceRegistered() {
|
|
1452
|
+
const device = this.$webex.internal.device;
|
|
1453
|
+
if (device && !device.registered && device.register) {
|
|
1454
|
+
await device.register();
|
|
1455
|
+
this.wxAppDeviceRegisteredByCc = true;
|
|
1456
|
+
_loggerProxy.default.log('WxApp: device registered for cross-client publish', {
|
|
1457
|
+
module: _constants.CC_FILE,
|
|
1458
|
+
method: _constants.METHODS.ENSURE_WXAPP_MERCURY_CONNECTED
|
|
1459
|
+
});
|
|
1460
|
+
}
|
|
1461
|
+
}
|
|
1462
|
+
async ensureWxAppMercuryConnected() {
|
|
1463
|
+
const mercury = this.$webex.internal.mercury;
|
|
1464
|
+
await this.ensureWxAppDeviceRegistered();
|
|
1465
|
+
if (mercury && !mercury.connected) {
|
|
1466
|
+
await mercury.connect();
|
|
1467
|
+
this.wxAppMercuryConnectedByCc = true;
|
|
1468
|
+
_loggerProxy.default.log('WxApp mute sync: mercury connected', {
|
|
1469
|
+
module: _constants.CC_FILE,
|
|
1470
|
+
method: _constants.METHODS.ENSURE_WXAPP_MERCURY_CONNECTED
|
|
1471
|
+
});
|
|
1472
|
+
}
|
|
1473
|
+
}
|
|
1474
|
+
|
|
1475
|
+
/**
|
|
1476
|
+
* Disconnects Mercury and unregisters the device when wxApp mute sync opened them.
|
|
1477
|
+
* @private
|
|
1478
|
+
*/
|
|
1479
|
+
async releaseWxAppMercuryResources() {
|
|
1480
|
+
const mercury = this.$webex.internal.mercury;
|
|
1481
|
+
const device = this.$webex.internal.device;
|
|
1482
|
+
if (this.wxAppMercuryConnectedByCc && mercury?.connected) {
|
|
1483
|
+
try {
|
|
1484
|
+
await mercury.disconnect();
|
|
1485
|
+
this.wxAppMercuryConnectedByCc = false;
|
|
1486
|
+
_loggerProxy.default.log('WxApp mute sync: mercury disconnected', {
|
|
1487
|
+
module: _constants.CC_FILE,
|
|
1488
|
+
method: _constants.METHODS.ENSURE_WXAPP_MERCURY_CONNECTED
|
|
1489
|
+
});
|
|
1490
|
+
} catch (error) {
|
|
1491
|
+
_loggerProxy.default.error(`Failed to disconnect wxApp Mercury: ${error}`, {
|
|
1492
|
+
module: _constants.CC_FILE,
|
|
1493
|
+
method: _constants.METHODS.ENSURE_WXAPP_MERCURY_CONNECTED
|
|
1494
|
+
});
|
|
1495
|
+
}
|
|
1496
|
+
}
|
|
1497
|
+
if (this.wxAppDeviceRegisteredByCc && device?.registered && device.unregister) {
|
|
1498
|
+
try {
|
|
1499
|
+
// @ts-ignore
|
|
1500
|
+
await device.unregister();
|
|
1501
|
+
this.wxAppDeviceRegisteredByCc = false;
|
|
1502
|
+
_loggerProxy.default.log('WxApp mute sync: device unregistered', {
|
|
1503
|
+
module: _constants.CC_FILE,
|
|
1504
|
+
method: _constants.METHODS.ENSURE_WXAPP_MERCURY_CONNECTED
|
|
1505
|
+
});
|
|
1506
|
+
} catch (error) {
|
|
1507
|
+
_loggerProxy.default.error(`Failed to unregister wxApp device: ${error}`, {
|
|
1508
|
+
module: _constants.CC_FILE,
|
|
1509
|
+
method: _constants.METHODS.ENSURE_WXAPP_MERCURY_CONNECTED
|
|
1510
|
+
});
|
|
1511
|
+
}
|
|
1512
|
+
} else if (this.wxAppDeviceRegisteredByCc) {
|
|
1513
|
+
this.wxAppDeviceRegisteredByCc = false;
|
|
1514
|
+
}
|
|
1515
|
+
}
|
|
1516
|
+
|
|
1517
|
+
/**
|
|
1518
|
+
* Clears wxApp runtime state and feature-owned resources. Publish failures are logged;
|
|
1519
|
+
* optional rethrow for deregister when callers need to surface usersub errors.
|
|
1520
|
+
* @private
|
|
1521
|
+
*/
|
|
1522
|
+
async teardownWxAppLocalState(options) {
|
|
1523
|
+
this.clearWxAppFalsePublishRetryTimer();
|
|
1524
|
+
let publishError;
|
|
1525
|
+
try {
|
|
1526
|
+
const shouldForceFalsePublish = this.isWxBetterTogetherEnabled() || this.webexCrossClientService.isAnswerCallsStateActive();
|
|
1527
|
+
await this.publishAnswerOnWebexCrossClientState(false, {
|
|
1528
|
+
force: shouldForceFalsePublish
|
|
1529
|
+
});
|
|
1530
|
+
} catch (error) {
|
|
1531
|
+
publishError = error;
|
|
1532
|
+
_loggerProxy.default.error(`Failed to publish answer-calls-on-wxcc false during wxApp teardown: ${error}`, {
|
|
1533
|
+
module: _constants.CC_FILE,
|
|
1534
|
+
method: _constants.METHODS.SET_MANAGE_WEBEX_CALLING_IN_WXCC
|
|
1535
|
+
});
|
|
1536
|
+
}
|
|
1537
|
+
this.webexCrossClientService.teardown();
|
|
1538
|
+
this.wxAppTelephonyMercurySync.unsubscribe();
|
|
1539
|
+
await this.releaseWxAppMercuryResources();
|
|
1540
|
+
if (options?.clearInitFlag) {
|
|
1541
|
+
this.resetEnableWxBetterTogetherConfig();
|
|
1542
|
+
}
|
|
1543
|
+
if (publishError) {
|
|
1544
|
+
this.scheduleCompensatingFalsePublishRetry();
|
|
1545
|
+
}
|
|
1546
|
+
if (options?.rethrowPublishError && publishError) {
|
|
1547
|
+
throw publishError;
|
|
1548
|
+
}
|
|
1549
|
+
return {
|
|
1550
|
+
publishError: publishError ?? undefined
|
|
1551
|
+
};
|
|
1552
|
+
}
|
|
1553
|
+
async ensureWxAppMercuryAndSubscribe() {
|
|
1554
|
+
if (!this.isWxBetterTogetherEnabled()) {
|
|
1555
|
+
return;
|
|
1556
|
+
}
|
|
1557
|
+
if (this.getCurrentStationLoginOption() === _types.LoginOption.BROWSER) {
|
|
1558
|
+
return;
|
|
1559
|
+
}
|
|
1560
|
+
const agentId = this.agentConfig?.agentId;
|
|
1561
|
+
if (!agentId) {
|
|
1562
|
+
_loggerProxy.default.error('Cannot subscribe wxApp mute sync: agentId unavailable', {
|
|
1563
|
+
module: _constants.CC_FILE,
|
|
1564
|
+
method: _constants.METHODS.SYNC_WXAPP_MUTE_FROM_MERCURY
|
|
1565
|
+
});
|
|
1566
|
+
return;
|
|
1567
|
+
}
|
|
1568
|
+
try {
|
|
1569
|
+
await this.ensureWxAppMercuryConnected();
|
|
1570
|
+
this.wxAppTelephonyMercurySync.subscribe(agentId, (callId, muted) => {
|
|
1571
|
+
this.taskManager.applyWxAppMuteStateFromSync(callId, muted);
|
|
1572
|
+
});
|
|
1573
|
+
} catch (error) {
|
|
1574
|
+
_loggerProxy.default.error(`Failed to ensure wxApp Mercury mute sync: ${error}`, {
|
|
1575
|
+
module: _constants.CC_FILE,
|
|
1576
|
+
method: _constants.METHODS.SYNC_WXAPP_MUTE_FROM_MERCURY
|
|
1577
|
+
});
|
|
1578
|
+
this.wxAppTelephonyMercurySync.unsubscribe();
|
|
1579
|
+
await this.releaseWxAppMercuryResources();
|
|
1580
|
+
throw error;
|
|
1581
|
+
}
|
|
1582
|
+
}
|
|
1583
|
+
async publishAnswerOnWebexCrossClientState(enable, options) {
|
|
1584
|
+
if (enable && !this.isWxBetterTogetherEnabled()) {
|
|
1585
|
+
return;
|
|
1586
|
+
}
|
|
1587
|
+
if (!enable && !options?.force && !this.webexCrossClientService.isAnswerCallsStateActive()) {
|
|
1588
|
+
return;
|
|
1589
|
+
}
|
|
1590
|
+
const userId = this.$webex.internal.device?.userId;
|
|
1591
|
+
if (!userId) {
|
|
1592
|
+
return;
|
|
1593
|
+
}
|
|
1594
|
+
await this.webexCrossClientService.setManageWebexCallingInWxcc(enable, {
|
|
1595
|
+
userId
|
|
1596
|
+
});
|
|
1597
|
+
if (enable) {
|
|
1598
|
+
this.clearWxAppFalsePublishRetryTimer();
|
|
1599
|
+
}
|
|
1600
|
+
}
|
|
1601
|
+
|
|
1024
1602
|
/**
|
|
1025
1603
|
* Initializes event listeners for the Contact Center service
|
|
1026
1604
|
* Sets up handlers for connection state changes and other core events
|
|
@@ -1052,13 +1630,13 @@ class ContactCenter extends _webexCore.WebexPlugin {
|
|
|
1052
1630
|
async handleConnectionLost(msg) {
|
|
1053
1631
|
if (msg.isConnectionLost) {
|
|
1054
1632
|
// TODO: Emit an event saying connection is lost
|
|
1055
|
-
_loggerProxy.default.
|
|
1633
|
+
_loggerProxy.default.log('event=handleConnectionLost | Connection lost', {
|
|
1056
1634
|
module: _constants.CC_FILE,
|
|
1057
1635
|
method: _constants.METHODS.HANDLE_CONNECTION_LOST
|
|
1058
1636
|
});
|
|
1059
1637
|
} else if (msg.isSocketReconnected) {
|
|
1060
1638
|
// TODO: Emit an event saying connection is re-estabilished
|
|
1061
|
-
_loggerProxy.default.
|
|
1639
|
+
_loggerProxy.default.log('event=handleConnectionReconnect | Connection reconnected attempting to request silent relogin', {
|
|
1062
1640
|
module: _constants.CC_FILE,
|
|
1063
1641
|
method: _constants.METHODS.HANDLE_CONNECTION_LOST
|
|
1064
1642
|
});
|
|
@@ -1073,7 +1651,7 @@ class ContactCenter extends _webexCore.WebexPlugin {
|
|
|
1073
1651
|
* @private
|
|
1074
1652
|
*/
|
|
1075
1653
|
async silentRelogin() {
|
|
1076
|
-
_loggerProxy.default.
|
|
1654
|
+
_loggerProxy.default.log('Starting silent relogin process', {
|
|
1077
1655
|
module: _constants.CC_FILE,
|
|
1078
1656
|
method: _constants.METHODS.SILENT_RELOGIN
|
|
1079
1657
|
});
|
|
@@ -1095,7 +1673,7 @@ class ContactCenter extends _webexCore.WebexPlugin {
|
|
|
1095
1673
|
this.agentConfig.currentTeamId = reLoginResponse.data.teamId;
|
|
1096
1674
|
await this.handleDeviceType(deviceType, dn);
|
|
1097
1675
|
if (lastStateChangeReason === 'agent-wss-disconnect') {
|
|
1098
|
-
_loggerProxy.default.
|
|
1676
|
+
_loggerProxy.default.log('event=requestAutoStateChange | Requesting state change to available on socket reconnect', {
|
|
1099
1677
|
module: _constants.CC_FILE,
|
|
1100
1678
|
method: _constants.METHODS.SILENT_RELOGIN
|
|
1101
1679
|
});
|
|
@@ -1119,8 +1697,7 @@ class ContactCenter extends _webexCore.WebexPlugin {
|
|
|
1119
1697
|
}
|
|
1120
1698
|
this.agentConfig.lastStateAuxCodeId = auxCodeId;
|
|
1121
1699
|
this.agentConfig.isAgentLoggedIn = true;
|
|
1122
|
-
|
|
1123
|
-
this.services.webSocketManager.on('message', this.handleWebsocketMessage);
|
|
1700
|
+
await this.ensureWxAppPostStationLogin();
|
|
1124
1701
|
_loggerProxy.default.log(`Silent relogin process completed successfully with login Option: ${reLoginResponse.data.deviceType} teamId: ${reLoginResponse.data.teamId}`, {
|
|
1125
1702
|
module: _constants.CC_FILE,
|
|
1126
1703
|
method: _constants.METHODS.SILENT_RELOGIN,
|
|
@@ -1155,6 +1732,13 @@ class ContactCenter extends _webexCore.WebexPlugin {
|
|
|
1155
1732
|
this.agentConfig.deviceType = deviceType;
|
|
1156
1733
|
switch (deviceType) {
|
|
1157
1734
|
case _types.LoginOption.BROWSER:
|
|
1735
|
+
if (this.isWebRTCRegistrationDisabled()) {
|
|
1736
|
+
_loggerProxy.default.info('Skipping web calling line registration because disableWebRTCRegistration is enabled', {
|
|
1737
|
+
module: _constants.CC_FILE,
|
|
1738
|
+
method: _constants.METHODS.HANDLE_DEVICE_TYPE
|
|
1739
|
+
});
|
|
1740
|
+
break;
|
|
1741
|
+
}
|
|
1158
1742
|
try {
|
|
1159
1743
|
await this.webCallingService.registerWebCallingLine();
|
|
1160
1744
|
} catch (error) {
|
|
@@ -1336,6 +1920,196 @@ class ContactCenter extends _webexCore.WebexPlugin {
|
|
|
1336
1920
|
}
|
|
1337
1921
|
}
|
|
1338
1922
|
|
|
1923
|
+
/**
|
|
1924
|
+
* Accepts a campaign preview contact, initiating the outbound call.
|
|
1925
|
+
*
|
|
1926
|
+
* When a campaign manager reserves a contact for an agent, the agent receives an
|
|
1927
|
+
* `AgentOfferCampaignReservation` event. The agent can then accept the preview contact
|
|
1928
|
+
* to initiate the outbound call.
|
|
1929
|
+
*
|
|
1930
|
+
* @param {PreviewContactPayload} payload - The preview contact payload containing interactionId and campaignId (campaign name, not UUID).
|
|
1931
|
+
* @returns {Promise<TaskResponse>} Promise resolving with agent contact on success.
|
|
1932
|
+
* @throws {Error} If the operation fails (network error, customer unavailable, etc.)
|
|
1933
|
+
*
|
|
1934
|
+
* @example
|
|
1935
|
+
* ```typescript
|
|
1936
|
+
* webex.cc.on('task:campaignPreviewReservation', async (task) => {
|
|
1937
|
+
* const { interactionId } = task.data;
|
|
1938
|
+
* // campaignId is the campaign name (e.g. "MyCampaign"), not a UUID
|
|
1939
|
+
* const campaignId = task.data.interaction.callProcessingDetails.campaignId;
|
|
1940
|
+
*
|
|
1941
|
+
* const result = await webex.cc.acceptPreviewContact({ interactionId, campaignId });
|
|
1942
|
+
* });
|
|
1943
|
+
* ```
|
|
1944
|
+
*/
|
|
1945
|
+
async acceptPreviewContact(payload) {
|
|
1946
|
+
_loggerProxy.default.info('Accepting campaign preview contact', {
|
|
1947
|
+
module: _constants.CC_FILE,
|
|
1948
|
+
method: _constants.METHODS.ACCEPT_PREVIEW_CONTACT
|
|
1949
|
+
});
|
|
1950
|
+
try {
|
|
1951
|
+
this.metricsManager.timeEvent([_constants4.METRIC_EVENT_NAMES.CAMPAIGN_PREVIEW_ACCEPT_SUCCESS, _constants4.METRIC_EVENT_NAMES.CAMPAIGN_PREVIEW_ACCEPT_FAILED]);
|
|
1952
|
+
const result = await this.services.dialer.acceptPreviewContact({
|
|
1953
|
+
data: payload
|
|
1954
|
+
});
|
|
1955
|
+
this.metricsManager.trackEvent(_constants4.METRIC_EVENT_NAMES.CAMPAIGN_PREVIEW_ACCEPT_SUCCESS, {
|
|
1956
|
+
..._MetricsManager.default.getCommonTrackingFieldForAQMResponse(result),
|
|
1957
|
+
interactionId: payload.interactionId,
|
|
1958
|
+
campaignId: payload.campaignId
|
|
1959
|
+
}, ['behavioral', 'business', 'operational']);
|
|
1960
|
+
_loggerProxy.default.log('Campaign preview contact accepted successfully', {
|
|
1961
|
+
module: _constants.CC_FILE,
|
|
1962
|
+
method: _constants.METHODS.ACCEPT_PREVIEW_CONTACT,
|
|
1963
|
+
trackingId: result.trackingId,
|
|
1964
|
+
interactionId: payload.interactionId
|
|
1965
|
+
});
|
|
1966
|
+
return result;
|
|
1967
|
+
} catch (error) {
|
|
1968
|
+
const failure = error.details;
|
|
1969
|
+
this.metricsManager.trackEvent(_constants4.METRIC_EVENT_NAMES.CAMPAIGN_PREVIEW_ACCEPT_FAILED, {
|
|
1970
|
+
..._MetricsManager.default.getCommonTrackingFieldForAQMResponseFailed(failure),
|
|
1971
|
+
interactionId: payload.interactionId,
|
|
1972
|
+
campaignId: payload.campaignId
|
|
1973
|
+
}, ['behavioral', 'business', 'operational']);
|
|
1974
|
+
const {
|
|
1975
|
+
error: detailedError
|
|
1976
|
+
} = (0, _Utils.getErrorDetails)(error, _constants.METHODS.ACCEPT_PREVIEW_CONTACT, _constants.CC_FILE);
|
|
1977
|
+
throw detailedError;
|
|
1978
|
+
}
|
|
1979
|
+
}
|
|
1980
|
+
|
|
1981
|
+
/**
|
|
1982
|
+
* Skips a campaign preview contact, requesting the next contact from the campaign.
|
|
1983
|
+
*
|
|
1984
|
+
* When a campaign manager reserves a contact for an agent, the agent receives an
|
|
1985
|
+
* `AgentOfferCampaignReservation` event. Instead of accepting, the agent can skip the
|
|
1986
|
+
* preview contact to move to the next contact in the campaign.
|
|
1987
|
+
*
|
|
1988
|
+
* @param {PreviewContactPayload} payload - The preview contact payload containing interactionId and campaignId (campaign name, not UUID).
|
|
1989
|
+
* @returns {Promise<TaskResponse>} Promise resolving with agent contact on success.
|
|
1990
|
+
* @throws {Error} If the operation fails (network error, etc.)
|
|
1991
|
+
*
|
|
1992
|
+
* @example
|
|
1993
|
+
* ```typescript
|
|
1994
|
+
* webex.cc.on('task:campaignPreviewReservation', async (task) => {
|
|
1995
|
+
* const { interactionId } = task.data;
|
|
1996
|
+
* const campaignId = task.data.interaction.callProcessingDetails.campaignId;
|
|
1997
|
+
*
|
|
1998
|
+
* const result = await webex.cc.skipPreviewContact({ interactionId, campaignId });
|
|
1999
|
+
* });
|
|
2000
|
+
* ```
|
|
2001
|
+
*/
|
|
2002
|
+
async skipPreviewContact(payload) {
|
|
2003
|
+
const task = this.taskManager.getTask(payload.interactionId);
|
|
2004
|
+
if (task?.data?.interaction?.callProcessingDetails?.campaignPreviewSkipDisabled === 'true') {
|
|
2005
|
+
_loggerProxy.default.warn('Skip action is disabled for this campaign preview contact', {
|
|
2006
|
+
module: _constants.CC_FILE,
|
|
2007
|
+
method: _constants.METHODS.SKIP_PREVIEW_CONTACT,
|
|
2008
|
+
interactionId: payload.interactionId
|
|
2009
|
+
});
|
|
2010
|
+
throw new Error('Skip action is disabled for this campaign preview contact');
|
|
2011
|
+
}
|
|
2012
|
+
_loggerProxy.default.info('Skipping campaign preview contact', {
|
|
2013
|
+
module: _constants.CC_FILE,
|
|
2014
|
+
method: _constants.METHODS.SKIP_PREVIEW_CONTACT
|
|
2015
|
+
});
|
|
2016
|
+
try {
|
|
2017
|
+
this.metricsManager.timeEvent([_constants4.METRIC_EVENT_NAMES.CAMPAIGN_PREVIEW_SKIP_SUCCESS, _constants4.METRIC_EVENT_NAMES.CAMPAIGN_PREVIEW_SKIP_FAILED]);
|
|
2018
|
+
const result = await this.services.dialer.skipPreviewContact({
|
|
2019
|
+
data: payload
|
|
2020
|
+
});
|
|
2021
|
+
this.metricsManager.trackEvent(_constants4.METRIC_EVENT_NAMES.CAMPAIGN_PREVIEW_SKIP_SUCCESS, {
|
|
2022
|
+
..._MetricsManager.default.getCommonTrackingFieldForAQMResponse(result),
|
|
2023
|
+
interactionId: payload.interactionId,
|
|
2024
|
+
campaignId: payload.campaignId
|
|
2025
|
+
}, ['behavioral', 'business', 'operational']);
|
|
2026
|
+
_loggerProxy.default.log('Campaign preview contact skipped successfully', {
|
|
2027
|
+
module: _constants.CC_FILE,
|
|
2028
|
+
method: _constants.METHODS.SKIP_PREVIEW_CONTACT,
|
|
2029
|
+
trackingId: result.trackingId,
|
|
2030
|
+
interactionId: payload.interactionId
|
|
2031
|
+
});
|
|
2032
|
+
return result;
|
|
2033
|
+
} catch (error) {
|
|
2034
|
+
const failure = error.details;
|
|
2035
|
+
this.metricsManager.trackEvent(_constants4.METRIC_EVENT_NAMES.CAMPAIGN_PREVIEW_SKIP_FAILED, {
|
|
2036
|
+
..._MetricsManager.default.getCommonTrackingFieldForAQMResponseFailed(failure),
|
|
2037
|
+
interactionId: payload.interactionId,
|
|
2038
|
+
campaignId: payload.campaignId
|
|
2039
|
+
}, ['behavioral', 'business', 'operational']);
|
|
2040
|
+
const {
|
|
2041
|
+
error: detailedError
|
|
2042
|
+
} = (0, _Utils.getErrorDetails)(error, _constants.METHODS.SKIP_PREVIEW_CONTACT, _constants.CC_FILE);
|
|
2043
|
+
throw detailedError;
|
|
2044
|
+
}
|
|
2045
|
+
}
|
|
2046
|
+
|
|
2047
|
+
/**
|
|
2048
|
+
* Removes a campaign preview contact from the campaign list entirely.
|
|
2049
|
+
*
|
|
2050
|
+
* When a campaign manager reserves a contact for an agent, the agent receives an
|
|
2051
|
+
* `AgentOfferCampaignReservation` event. Instead of accepting or skipping, the agent can
|
|
2052
|
+
* remove the preview contact to permanently take it out of the campaign contact list.
|
|
2053
|
+
*
|
|
2054
|
+
* @param {PreviewContactPayload} payload - The preview contact payload containing interactionId and campaignId (campaign name, not UUID).
|
|
2055
|
+
* @returns {Promise<TaskResponse>} Promise resolving with agent contact on success.
|
|
2056
|
+
* @throws {Error} If the operation fails (network error, etc.)
|
|
2057
|
+
*
|
|
2058
|
+
* @example
|
|
2059
|
+
* ```typescript
|
|
2060
|
+
* webex.cc.on('task:campaignPreviewReservation', async (task) => {
|
|
2061
|
+
* const { interactionId } = task.data;
|
|
2062
|
+
* const campaignId = task.data.interaction.callProcessingDetails.campaignId;
|
|
2063
|
+
*
|
|
2064
|
+
* const result = await webex.cc.removePreviewContact({ interactionId, campaignId });
|
|
2065
|
+
* });
|
|
2066
|
+
* ```
|
|
2067
|
+
*/
|
|
2068
|
+
async removePreviewContact(payload) {
|
|
2069
|
+
const task = this.taskManager.getTask(payload.interactionId);
|
|
2070
|
+
if (task?.data?.interaction?.callProcessingDetails?.campaignPreviewRemoveDisabled === 'true') {
|
|
2071
|
+
_loggerProxy.default.warn('Remove action is disabled for this campaign preview contact', {
|
|
2072
|
+
module: _constants.CC_FILE,
|
|
2073
|
+
method: _constants.METHODS.REMOVE_PREVIEW_CONTACT,
|
|
2074
|
+
interactionId: payload.interactionId
|
|
2075
|
+
});
|
|
2076
|
+
throw new Error('Remove action is disabled for this campaign preview contact');
|
|
2077
|
+
}
|
|
2078
|
+
_loggerProxy.default.info('Removing campaign preview contact', {
|
|
2079
|
+
module: _constants.CC_FILE,
|
|
2080
|
+
method: _constants.METHODS.REMOVE_PREVIEW_CONTACT
|
|
2081
|
+
});
|
|
2082
|
+
try {
|
|
2083
|
+
this.metricsManager.timeEvent([_constants4.METRIC_EVENT_NAMES.CAMPAIGN_PREVIEW_REMOVE_SUCCESS, _constants4.METRIC_EVENT_NAMES.CAMPAIGN_PREVIEW_REMOVE_FAILED]);
|
|
2084
|
+
const result = await this.services.dialer.removePreviewContact({
|
|
2085
|
+
data: payload
|
|
2086
|
+
});
|
|
2087
|
+
this.metricsManager.trackEvent(_constants4.METRIC_EVENT_NAMES.CAMPAIGN_PREVIEW_REMOVE_SUCCESS, {
|
|
2088
|
+
..._MetricsManager.default.getCommonTrackingFieldForAQMResponse(result),
|
|
2089
|
+
interactionId: payload.interactionId,
|
|
2090
|
+
campaignId: payload.campaignId
|
|
2091
|
+
}, ['behavioral', 'business', 'operational']);
|
|
2092
|
+
_loggerProxy.default.log('Campaign preview contact removed successfully', {
|
|
2093
|
+
module: _constants.CC_FILE,
|
|
2094
|
+
method: _constants.METHODS.REMOVE_PREVIEW_CONTACT,
|
|
2095
|
+
trackingId: result.trackingId,
|
|
2096
|
+
interactionId: payload.interactionId
|
|
2097
|
+
});
|
|
2098
|
+
return result;
|
|
2099
|
+
} catch (error) {
|
|
2100
|
+
const failure = error.details;
|
|
2101
|
+
this.metricsManager.trackEvent(_constants4.METRIC_EVENT_NAMES.CAMPAIGN_PREVIEW_REMOVE_FAILED, {
|
|
2102
|
+
..._MetricsManager.default.getCommonTrackingFieldForAQMResponseFailed(failure),
|
|
2103
|
+
interactionId: payload.interactionId,
|
|
2104
|
+
campaignId: payload.campaignId
|
|
2105
|
+
}, ['behavioral', 'business', 'operational']);
|
|
2106
|
+
const {
|
|
2107
|
+
error: detailedError
|
|
2108
|
+
} = (0, _Utils.getErrorDetails)(error, _constants.METHODS.REMOVE_PREVIEW_CONTACT, _constants.CC_FILE);
|
|
2109
|
+
throw detailedError;
|
|
2110
|
+
}
|
|
2111
|
+
}
|
|
2112
|
+
|
|
1339
2113
|
/**
|
|
1340
2114
|
* Fetches outdial ANI (Automatic Number Identification) entries for an outdial ANI ID.
|
|
1341
2115
|
*
|
|
@@ -1467,6 +2241,7 @@ class ContactCenter extends _webexCore.WebexPlugin {
|
|
|
1467
2241
|
/**
|
|
1468
2242
|
* Updates the agent device type and login configuration.
|
|
1469
2243
|
* 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).
|
|
2244
|
+
* Change to any field of the profile is allowed;
|
|
1470
2245
|
*
|
|
1471
2246
|
* @param {AgentDeviceUpdate} data Configuration containing:
|
|
1472
2247
|
* - loginOption: New device type ('BROWSER', 'EXTENSION', 'AGENT_DN')
|
|
@@ -1500,24 +2275,8 @@ class ContactCenter extends _webexCore.WebexPlugin {
|
|
|
1500
2275
|
trackingId
|
|
1501
2276
|
});
|
|
1502
2277
|
try {
|
|
1503
|
-
// Only block if both loginOption AND teamId remain unchanged
|
|
1504
|
-
if (this.webCallingService?.loginOption === data.loginOption && data.teamId === this.agentConfig.currentTeamId) {
|
|
1505
|
-
const message = 'Will not proceed with device update as new Device type is same as current device type and teamId is same as current teamId';
|
|
1506
|
-
const err = new Error(message);
|
|
1507
|
-
err.details = {
|
|
1508
|
-
type: 'Identical Device Change Failure',
|
|
1509
|
-
orgId: this.$webex.credentials.getOrgId(),
|
|
1510
|
-
trackingId,
|
|
1511
|
-
data: {
|
|
1512
|
-
agentId: this.agentConfig.agentId,
|
|
1513
|
-
reasonCode: 'R002',
|
|
1514
|
-
reason: message
|
|
1515
|
-
}
|
|
1516
|
-
};
|
|
1517
|
-
throw err;
|
|
1518
|
-
}
|
|
1519
2278
|
await this.stationLogout({
|
|
1520
|
-
logoutReason: 'User requested agent
|
|
2279
|
+
logoutReason: 'User requested agent profile update'
|
|
1521
2280
|
});
|
|
1522
2281
|
const loginPayload = {
|
|
1523
2282
|
teamId: data.teamId,
|
|
@@ -1555,8 +2314,8 @@ class ContactCenter extends _webexCore.WebexPlugin {
|
|
|
1555
2314
|
}
|
|
1556
2315
|
|
|
1557
2316
|
/**
|
|
1558
|
-
* Returns paginated entry points
|
|
1559
|
-
*
|
|
2317
|
+
* Returns paginated entry points using the EntryPoint service defaults.
|
|
2318
|
+
* Existing request parameters can override those defaults.
|
|
1560
2319
|
* @public
|
|
1561
2320
|
*/
|
|
1562
2321
|
async getEntryPoints(params = {}) {
|
|
@@ -1564,8 +2323,8 @@ class ContactCenter extends _webexCore.WebexPlugin {
|
|
|
1564
2323
|
}
|
|
1565
2324
|
|
|
1566
2325
|
/**
|
|
1567
|
-
* Returns paginated contact service queues
|
|
1568
|
-
*
|
|
2326
|
+
* Returns paginated contact service queues using the Queue service defaults.
|
|
2327
|
+
* Existing request parameters can override those defaults.
|
|
1569
2328
|
* @public
|
|
1570
2329
|
*/
|
|
1571
2330
|
async getQueues(params = {}) {
|