@webex/contact-center 3.12.0-next.16 → 3.12.0-next.161
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 +887 -0
- package/AGENTS.md +94 -0
- package/ai-docs/ARCHITECTURE.md +168 -0
- package/ai-docs/CONTRACTS.md +62 -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 +52 -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 +385 -0
- package/ai-docs/features/consult-transfer-list-policy/spec/feature-spec.md +362 -0
- package/ai-docs/features/contact-owner-change-refactor.md +78 -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 +888 -49
- package/dist/cc.js.map +1 -1
- package/dist/config.js +13 -0
- package/dist/config.js.map +1 -1
- package/dist/constants.js +38 -3
- package/dist/constants.js.map +1 -1
- package/dist/index.js +54 -17
- package/dist/index.js.map +1 -1
- package/dist/metrics/MetricsManager.js +16 -0
- package/dist/metrics/MetricsManager.js.map +1 -1
- package/dist/metrics/behavioral-events.js +185 -0
- package/dist/metrics/behavioral-events.js.map +1 -1
- package/dist/metrics/constants.js +54 -4
- 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 +202 -0
- package/dist/services/AnswerCallOnWebexService.js.map +1 -0
- package/dist/services/ApiAiAssistant.js +369 -14
- package/dist/services/ApiAiAssistant.js.map +1 -1
- 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/WebCallingService.js +10 -2
- package/dist/services/WebCallingService.js.map +1 -1
- package/dist/services/WebexCrossClientService.js +225 -0
- package/dist/services/WebexCrossClientService.js.map +1 -0
- package/dist/services/WxAppTelephonyMercurySync.js +111 -0
- package/dist/services/WxAppTelephonyMercurySync.js.map +1 -0
- package/dist/services/config/Util.js +48 -48
- package/dist/services/config/Util.js.map +1 -1
- package/dist/services/config/constants.js +56 -78
- package/dist/services/config/constants.js.map +1 -1
- package/dist/services/config/index.js +100 -226
- package/dist/services/config/index.js.map +1 -1
- package/dist/services/config/types.js +93 -24
- package/dist/services/config/types.js.map +1 -1
- package/dist/services/constants.js +11 -1
- package/dist/services/constants.js.map +1 -1
- package/dist/services/core/Err.js.map +1 -1
- package/dist/services/core/Utils.js +131 -32
- 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 +17 -11
- package/dist/services/core/aqm-reqs.js.map +1 -1
- package/dist/services/core/constants.js +9 -1
- package/dist/services/core/constants.js.map +1 -1
- package/dist/services/core/types.js.map +1 -1
- package/dist/services/core/websocket/WebSocketManager.js +19 -2
- package/dist/services/core/websocket/WebSocketManager.js.map +1 -1
- package/dist/services/core/websocket/types.js.map +1 -1
- package/dist/services/index.js +1 -1
- package/dist/services/index.js.map +1 -1
- package/dist/services/task/Task.js +955 -0
- package/dist/services/task/Task.js.map +1 -0
- package/dist/services/task/TaskFactory.js +50 -0
- package/dist/services/task/TaskFactory.js.map +1 -0
- package/dist/services/task/TaskManager.js +1272 -605
- package/dist/services/task/TaskManager.js.map +1 -1
- package/dist/services/task/TaskUtils.js +221 -27
- 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 +19 -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/digital/Digital.js +78 -0
- package/dist/services/task/digital/Digital.js.map +1 -0
- package/dist/services/task/state-machine/TaskStateMachine.js +982 -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 +379 -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 +215 -5
- package/dist/services/task/types.js.map +1 -1
- package/dist/services/task/voice/Voice.js +1504 -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/wxAppOfferObservability.js +145 -0
- package/dist/services/task/voice/wxAppOfferObservability.js.map +1 -0
- package/dist/services/task/voice/wxAppVoiceMethods.js +395 -0
- package/dist/services/task/voice/wxAppVoiceMethods.js.map +1 -0
- package/dist/services/wxAppDiagnosticLogging.js +159 -0
- package/dist/services/wxAppDiagnosticLogging.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 +152 -9
- package/dist/types/config.d.ts +13 -0
- package/dist/types/constants.d.ts +36 -1
- package/dist/types/index.d.ts +54 -20
- package/dist/types/metrics/MetricsManager.d.ts +6 -0
- package/dist/types/metrics/constants.d.ts +48 -1
- package/dist/types/services/AddressBook.d.ts +2 -1
- package/dist/types/services/AnswerCallOnWebexService.d.ts +38 -0
- package/dist/types/services/ApiAiAssistant.d.ts +67 -5
- package/dist/types/services/EntryPoint.d.ts +7 -5
- package/dist/types/services/Queue.d.ts +5 -3
- package/dist/types/services/UserPreference.d.ts +118 -0
- package/dist/types/services/WebexCrossClientService.d.ts +32 -0
- package/dist/types/services/WxAppTelephonyMercurySync.d.ts +28 -0
- package/dist/types/services/config/Util.d.ts +4 -8
- package/dist/types/services/config/constants.d.ts +49 -76
- package/dist/types/services/config/index.d.ts +16 -64
- package/dist/types/services/config/types.d.ts +240 -114
- package/dist/types/services/constants.d.ts +9 -0
- package/dist/types/services/core/Err.d.ts +2 -0
- package/dist/types/services/core/Utils.d.ts +43 -13
- package/dist/types/services/core/WebexRequest.d.ts +1 -0
- package/dist/types/services/core/constants.d.ts +7 -0
- package/dist/types/services/core/types.d.ts +2 -0
- package/dist/types/services/core/websocket/WebSocketManager.d.ts +1 -0
- package/dist/types/services/core/websocket/types.d.ts +1 -1
- package/dist/types/services/index.d.ts +1 -1
- package/dist/types/services/task/Task.d.ts +186 -0
- package/dist/types/services/task/TaskFactory.d.ts +14 -0
- package/dist/types/services/task/TaskUtils.d.ts +54 -2
- package/dist/types/services/task/WebexCallingUtils.d.ts +11 -0
- package/dist/types/services/task/constants.d.ts +17 -0
- package/dist/types/services/task/contact.d.ts +4 -0
- package/dist/types/services/task/digital/Digital.d.ts +23 -0
- package/dist/types/services/task/state-machine/TaskStateMachine.d.ts +1442 -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 +738 -66
- package/dist/types/services/task/voice/Voice.d.ts +241 -0
- package/dist/types/services/task/voice/WebRTC.d.ts +54 -0
- package/dist/types/services/task/voice/wxAppOfferObservability.d.ts +39 -0
- package/dist/types/services/task/voice/wxAppVoiceMethods.d.ts +68 -0
- package/dist/types/services/wxAppDiagnosticLogging.d.ts +63 -0
- package/dist/types/services/wxAppTelephonyUtils.d.ts +5 -0
- package/dist/types/types.d.ts +213 -11
- package/dist/types/utils/PageCache.d.ts +20 -3
- package/dist/types/webex.d.ts +1 -0
- package/dist/types.js +168 -6
- 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 +22 -2
- package/dist/webex.js.map +1 -1
- package/package.json +16 -12
- package/src/cc.ts +1137 -67
- package/src/config.ts +13 -0
- package/src/constants.ts +39 -1
- package/src/index.ts +62 -15
- package/src/metrics/MetricsManager.ts +16 -0
- 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 +971 -0
- package/src/metrics/behavioral-events.ts +190 -0
- package/src/metrics/constants.ts +59 -4
- package/src/services/AddressBook.ts +17 -6
- package/src/services/AnswerCallOnWebexService.ts +239 -0
- package/src/services/ApiAiAssistant.ts +494 -15
- package/src/services/EntryPoint.ts +59 -60
- package/src/services/Queue.ts +29 -12
- package/src/services/UserPreference.ts +509 -0
- package/src/services/WebCallingService.ts +16 -2
- package/src/services/WebexCrossClientService.ts +298 -0
- package/src/services/WxAppTelephonyMercurySync.ts +142 -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 +505 -0
- package/src/services/ai-docs/AGENTS.md +386 -0
- package/src/services/ai-docs/services-spec.md +512 -0
- package/src/services/config/Util.ts +54 -84
- package/src/services/config/ai-docs/AGENTS.md +250 -0
- package/src/services/config/ai-docs/ARCHITECTURE.md +413 -0
- package/src/services/config/ai-docs/config-spec.md +669 -0
- package/src/services/config/constants.ts +63 -85
- package/src/services/config/index.ts +116 -277
- package/src/services/config/types.ts +229 -125
- package/src/services/constants.ts +10 -0
- package/src/services/core/Err.ts +1 -0
- package/src/services/core/Utils.ts +151 -37
- 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 +797 -0
- package/src/services/core/aqm-reqs.ts +18 -12
- package/src/services/core/constants.ts +8 -0
- package/src/services/core/types.ts +33 -1
- package/src/services/core/websocket/WebSocketManager.ts +28 -2
- package/src/services/core/websocket/types.ts +1 -1
- package/src/services/index.ts +1 -1
- package/src/services/task/Task.ts +1211 -0
- package/src/services/task/TaskFactory.ts +82 -0
- package/src/services/task/TaskManager.ts +1585 -724
- package/src/services/task/TaskUtils.ts +316 -25
- 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 +1501 -0
- package/src/services/task/constants.ts +18 -0
- package/src/services/task/contact.ts +30 -0
- package/src/services/task/digital/Digital.ts +102 -0
- package/src/services/task/state-machine/TaskStateMachine.ts +1320 -0
- package/src/services/task/state-machine/actions.ts +741 -0
- package/src/services/task/state-machine/ai-docs/AGENTS.md +460 -0
- package/src/services/task/state-machine/ai-docs/ARCHITECTURE.md +1156 -0
- package/src/services/task/state-machine/ai-docs/task-state-machine-spec.md +2247 -0
- package/src/services/task/state-machine/constants.ts +172 -0
- package/src/services/task/state-machine/guards.ts +442 -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 +918 -70
- package/src/services/task/voice/Voice.ts +1878 -0
- package/src/services/task/voice/WebRTC.ts +194 -0
- package/src/services/task/voice/wxAppOfferObservability.ts +204 -0
- package/src/services/task/voice/wxAppVoiceMethods.ts +575 -0
- package/src/services/wxAppDiagnosticLogging.ts +286 -0
- package/src/services/wxAppTelephonyUtils.ts +14 -0
- package/src/types.ts +272 -13
- 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 +10 -0
- package/test/unit/fixtures/aiSummaryTestUtils.ts +40 -0
- package/test/unit/spec/cc.ts +3553 -107
- package/test/unit/spec/index.ts +885 -0
- package/test/unit/spec/logger-proxy.ts +70 -0
- package/test/unit/spec/metrics/MetricsManager.ts +25 -0
- package/test/unit/spec/metrics/behavioral-events.ts +60 -0
- package/test/unit/spec/services/AddressBook.ts +37 -6
- package/test/unit/spec/services/AnswerCallOnWebexService.ts +264 -0
- package/test/unit/spec/services/ApiAiAssistant.ts +442 -23
- 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 +45 -1
- package/test/unit/spec/services/WebexCrossClientService.ts +509 -0
- package/test/unit/spec/services/WxAppTelephonyMercurySync.ts +136 -0
- package/test/unit/spec/services/config/Util.ts +501 -0
- package/test/unit/spec/services/config/index.ts +317 -547
- package/test/unit/spec/services/core/Utils.ts +447 -8
- package/test/unit/spec/services/core/WebexRequest.ts +8 -7
- package/test/unit/spec/services/core/aqm-reqs.ts +142 -1
- package/test/unit/spec/services/core/websocket/WebSocketManager.ts +129 -53
- package/test/unit/spec/services/task/AutoWrapup.ts +63 -0
- package/test/unit/spec/services/task/Task.ts +2723 -0
- package/test/unit/spec/services/task/TaskFactory.ts +116 -0
- package/test/unit/spec/services/task/TaskManager.ts +4734 -1769
- package/test/unit/spec/services/task/TaskUtils.ts +307 -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/digital/Digital.ts +105 -0
- package/test/unit/spec/services/task/state-machine/TaskStateMachine.ts +4060 -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 +2355 -0
- package/test/unit/spec/services/task/voice/WebRTC.ts +235 -0
- package/test/unit/spec/services/task/voice/wxAppOfferObservability.ts +361 -0
- package/test/unit/spec/services/task/voice/wxAppVoiceMethods.ts +719 -0
- package/test/unit/spec/services/wxAppDiagnosticLogging.ts +179 -0
- package/test/unit/spec/wellnessSampleUtils.ts +288 -0
- package/typedoc.md +1 -1
- package/umd/contact-center.min.js +2 -2
- package/umd/contact-center.min.js.map +1 -1
- package/dist/services/task/index.js +0 -1530
- package/dist/services/task/index.js.map +0 -1
- package/dist/types/services/task/index.d.ts +0 -650
- package/src/services/task/index.ts +0 -1806
- package/test/unit/spec/services/task/index.ts +0 -2205
package/dist/cc.js
CHANGED
|
@@ -19,6 +19,10 @@ 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"));
|
|
25
|
+
var _wxAppDiagnosticLogging = require("./services/wxAppDiagnosticLogging");
|
|
22
26
|
var _types4 = require("./services/task/types");
|
|
23
27
|
var _MetricsManager = _interopRequireDefault(require("./metrics/MetricsManager"));
|
|
24
28
|
var _constants4 = require("./metrics/constants");
|
|
@@ -26,6 +30,7 @@ var _EntryPoint = require("./services/EntryPoint");
|
|
|
26
30
|
var _AddressBook = require("./services/AddressBook");
|
|
27
31
|
var _Queue = require("./services/Queue");
|
|
28
32
|
var _ApiAiAssistant = require("./services/ApiAiAssistant");
|
|
33
|
+
var _UserPreference = require("./services/UserPreference");
|
|
29
34
|
function _interopRequireDefault(e) { return e && e.__esModule ? e : { default: e }; }
|
|
30
35
|
/**
|
|
31
36
|
* @module CCPlugin
|
|
@@ -35,6 +40,13 @@ function _interopRequireDefault(e) { return e && e.__esModule ? e : { default: e
|
|
|
35
40
|
* with Webex Contact Center features through the WebexSDK.
|
|
36
41
|
*/
|
|
37
42
|
|
|
43
|
+
/**
|
|
44
|
+
* Typed allow-list of server-controlled websocket event names this SDK re-emits verbatim.
|
|
45
|
+
* Guards against emitting an arbitrary/unknown `data.type` supplied by the websocket payload.
|
|
46
|
+
* @ignore
|
|
47
|
+
*/
|
|
48
|
+
const CC_EVENT_ALLOW_LIST = new Set(Object.values(_types3.CC_EVENTS));
|
|
49
|
+
|
|
38
50
|
/**
|
|
39
51
|
* The main Contact Center plugin class that enables integration with Webex Contact Center.
|
|
40
52
|
*
|
|
@@ -118,7 +130,7 @@ function _interopRequireDefault(e) { return e && e.__esModule ? e : { default: e
|
|
|
118
130
|
*
|
|
119
131
|
* // Login with browser-based calling
|
|
120
132
|
* await cc.stationLogin({
|
|
121
|
-
* teamId: profile.teams[0].
|
|
133
|
+
* teamId: profile.teams[0].id,
|
|
122
134
|
* loginOption: 'BROWSER'
|
|
123
135
|
* });
|
|
124
136
|
*
|
|
@@ -184,6 +196,29 @@ class ContactCenter extends _webexCore.WebexPlugin {
|
|
|
184
196
|
* @private
|
|
185
197
|
*/
|
|
186
198
|
|
|
199
|
+
/**
|
|
200
|
+
* REST telephony for wxApp thick-client answer (WXCC-6026)
|
|
201
|
+
* @private
|
|
202
|
+
*/
|
|
203
|
+
|
|
204
|
+
/**
|
|
205
|
+
* usersub cross-client state for Webex App toast suppression
|
|
206
|
+
* @private
|
|
207
|
+
*/
|
|
208
|
+
|
|
209
|
+
/**
|
|
210
|
+
* Mercury telephony mute sync for wxApp thick-client answer
|
|
211
|
+
* @private
|
|
212
|
+
*/
|
|
213
|
+
|
|
214
|
+
/** True when wxApp mute sync opened Mercury (Extension/DN-only profiles). */
|
|
215
|
+
wxAppMercuryConnectedByCc = false;
|
|
216
|
+
|
|
217
|
+
/** True when wxApp mute sync registered the Webex device. */
|
|
218
|
+
wxAppDeviceRegisteredByCc = false;
|
|
219
|
+
static WXAPP_FALSE_PUBLISH_RETRY_DELAY_MS = 30_000;
|
|
220
|
+
static WXAPP_FALSE_PUBLISH_MAX_RETRIES = 3;
|
|
221
|
+
|
|
187
222
|
/**
|
|
188
223
|
* Core service managers for Contact Center operations
|
|
189
224
|
* Includes agent, connection, and configuration services
|
|
@@ -212,6 +247,16 @@ class ContactCenter extends _webexCore.WebexPlugin {
|
|
|
212
247
|
* @private
|
|
213
248
|
*/
|
|
214
249
|
|
|
250
|
+
/** Current login/relogin session used for agent-scoped wellness validation. */
|
|
251
|
+
|
|
252
|
+
/** Registered-session cache for the system WellbeingBreak idle code. */
|
|
253
|
+
|
|
254
|
+
/** Registration generation that owns the wellness idle-code cache and in-flight lookups. */
|
|
255
|
+
wellnessRegistrationGeneration = 0;
|
|
256
|
+
updateWellnessSession(agentSessionId) {
|
|
257
|
+
this.currentAgentSessionId = agentSessionId;
|
|
258
|
+
}
|
|
259
|
+
|
|
215
260
|
/**
|
|
216
261
|
* API instance for managing Webex Contact Center entry points
|
|
217
262
|
* Provides functionality to fetch entry points with caching support
|
|
@@ -274,6 +319,36 @@ class ContactCenter extends _webexCore.WebexPlugin {
|
|
|
274
319
|
* ```
|
|
275
320
|
*/
|
|
276
321
|
|
|
322
|
+
/**
|
|
323
|
+
* API instance for managing Webex Contact Center user preferences
|
|
324
|
+
* Provides functionality to get, create, update, and delete user preferences
|
|
325
|
+
* @type {UserPreference}
|
|
326
|
+
* @public
|
|
327
|
+
* @example
|
|
328
|
+
* ```typescript
|
|
329
|
+
* const cc = webex.cc;
|
|
330
|
+
* await cc.register();
|
|
331
|
+
* await cc.stationLogin({ teamId: 'team123', loginOption: 'BROWSER' });
|
|
332
|
+
*
|
|
333
|
+
* // Get user preferences for current user
|
|
334
|
+
* const preferences = await cc.userPreference.getUserPreference();
|
|
335
|
+
*
|
|
336
|
+
* // Create new user preferences
|
|
337
|
+
* const newPrefs = await cc.userPreference.createUserPreference({
|
|
338
|
+
* userId: 'user123',
|
|
339
|
+
* preferences: { e911Reminder: true }
|
|
340
|
+
* });
|
|
341
|
+
*
|
|
342
|
+
* // Update user preferences
|
|
343
|
+
* const updatedPrefs = await cc.userPreference.updateUserPreference('user123', {
|
|
344
|
+
* preferences: { e911Reminder: false }
|
|
345
|
+
* });
|
|
346
|
+
*
|
|
347
|
+
* // Delete user preferences
|
|
348
|
+
* await cc.userPreference.deleteUserPreference('user123');
|
|
349
|
+
* ```
|
|
350
|
+
*/
|
|
351
|
+
|
|
277
352
|
/**
|
|
278
353
|
* API instance for AI Assistant operations such as transcript controls.
|
|
279
354
|
* @type {ApiAIAssistant}
|
|
@@ -301,6 +376,7 @@ class ContactCenter extends _webexCore.WebexPlugin {
|
|
|
301
376
|
this.$webex.once(_constants.READY, () => {
|
|
302
377
|
// @ts-ignore
|
|
303
378
|
this.$config = this.config;
|
|
379
|
+
this.validatePluginConfig();
|
|
304
380
|
|
|
305
381
|
/**
|
|
306
382
|
* This is used for handling the async requests by sending webex.request and wait for corresponding websocket event.
|
|
@@ -312,13 +388,20 @@ class ContactCenter extends _webexCore.WebexPlugin {
|
|
|
312
388
|
webex: this.$webex,
|
|
313
389
|
connectionConfig: this.getConnectionConfig()
|
|
314
390
|
});
|
|
315
|
-
this.services.webSocketManager.on('message', this.handleWebsocketMessage);
|
|
316
391
|
this.webCallingService = new _WebCallingService.default(this.$webex);
|
|
317
|
-
this.
|
|
392
|
+
this.answerCallOnWebexService = new _AnswerCallOnWebexService.default(this.$webex);
|
|
393
|
+
this.webexCrossClientService = new _WebexCrossClientService.default(this.$webex);
|
|
394
|
+
this.wxAppTelephonyMercurySync = new _WxAppTelephonyMercurySync.default(this.$webex);
|
|
395
|
+
this.apiAIAssistant = new _ApiAiAssistant.ApiAIAssistant(this.$webex, () => ({
|
|
396
|
+
isWellnessBreakEnabled: this.agentConfig?.isWellnessBreakEnabled === true,
|
|
397
|
+
agentId: this.agentConfig?.agentId,
|
|
398
|
+
agentSessionId: this.currentAgentSessionId
|
|
399
|
+
}));
|
|
318
400
|
this.metricsManager = _MetricsManager.default.getInstance({
|
|
319
401
|
webex: this.$webex
|
|
320
402
|
});
|
|
321
|
-
this.taskManager = _TaskManager.default.getTaskManager(this.apiAIAssistant, this.services.contact, this.webCallingService, this.services.webSocketManager);
|
|
403
|
+
this.taskManager = _TaskManager.default.getTaskManager(this.apiAIAssistant, this.services.contact, this.webCallingService, this.services.webSocketManager, this.services.rtdWebSocketManager);
|
|
404
|
+
this.taskManager.setAnswerCallOnWebexService(this.answerCallOnWebexService);
|
|
322
405
|
this.incomingTaskListener();
|
|
323
406
|
|
|
324
407
|
// Initialize API instances
|
|
@@ -326,6 +409,7 @@ class ContactCenter extends _webexCore.WebexPlugin {
|
|
|
326
409
|
this.entryPoint = new _EntryPoint.EntryPoint(this.$webex);
|
|
327
410
|
this.addressBook = new _AddressBook.AddressBook(this.$webex, () => this.agentConfig?.addressBookId);
|
|
328
411
|
this.queue = new _Queue.Queue(this.$webex);
|
|
412
|
+
this.userPreference = new _UserPreference.UserPreference(this.$webex, () => this.agentConfig?.agentId);
|
|
329
413
|
_loggerProxy.default.initialize(this.$webex.logger);
|
|
330
414
|
});
|
|
331
415
|
}
|
|
@@ -350,6 +434,16 @@ class ContactCenter extends _webexCore.WebexPlugin {
|
|
|
350
434
|
this.trigger(_types4.TASK_EVENTS.TASK_HYDRATE, task);
|
|
351
435
|
};
|
|
352
436
|
|
|
437
|
+
/**
|
|
438
|
+
* Handles multi-login hydrate events for SDK instances without Mobius registration
|
|
439
|
+
* @private
|
|
440
|
+
* @param {ITask} task The task object associated with the multi-login hydrate
|
|
441
|
+
*/
|
|
442
|
+
handleTaskMultiLoginHydrate = task => {
|
|
443
|
+
// @ts-ignore
|
|
444
|
+
this.trigger(_types4.TASK_EVENTS.TASK_MULTI_LOGIN_HYDRATE, task);
|
|
445
|
+
};
|
|
446
|
+
|
|
353
447
|
/**
|
|
354
448
|
* Handles task merged events when tasks are combined eg: EPDN merge/transfer
|
|
355
449
|
* @private
|
|
@@ -369,8 +463,83 @@ class ContactCenter extends _webexCore.WebexPlugin {
|
|
|
369
463
|
// @ts-ignore
|
|
370
464
|
this.trigger(_types4.TASK_EVENTS.TASK_CAMPAIGN_PREVIEW_RESERVATION, task);
|
|
371
465
|
};
|
|
372
|
-
|
|
373
|
-
this.
|
|
466
|
+
trackInvalidWellnessEvent(reason) {
|
|
467
|
+
this.metricsManager.trackEvent(_constants4.METRIC_EVENT_NAMES.AI_ASSISTANT_WELLNESS_EVENT_INVALID, {
|
|
468
|
+
reason
|
|
469
|
+
}, ['operational']);
|
|
470
|
+
}
|
|
471
|
+
normalizeWellnessBreakEvent(payload) {
|
|
472
|
+
if (this.agentConfig?.isWellnessBreakEnabled !== true) {
|
|
473
|
+
this.trackInvalidWellnessEvent('wellness_disabled');
|
|
474
|
+
return null;
|
|
475
|
+
}
|
|
476
|
+
const notificationData = (0, _Utils.isRecord)(payload.data) ? payload.data : null;
|
|
477
|
+
const notificationDetails = notificationData && (0, _Utils.isRecord)(notificationData.notifDetails) ? notificationData.notifDetails : null;
|
|
478
|
+
const sessionData = notificationData && (0, _Utils.isRecord)(notificationData.data) ? notificationData.data : null;
|
|
479
|
+
const actionEvent = notificationDetails?.actionEvent;
|
|
480
|
+
if (payload.type !== _constants.WELLNESS_BREAK_HANDLER || notificationData?.notifType !== _constants.WELLNESS_BREAK_HANDLER || typeof actionEvent !== 'string') {
|
|
481
|
+
this.trackInvalidWellnessEvent('malformed_wellness_event');
|
|
482
|
+
return null;
|
|
483
|
+
}
|
|
484
|
+
if (!Object.values(_types.WELLNESS_BREAK_NOTIFICATION_ACTIONS).includes(actionEvent)) {
|
|
485
|
+
this.trackInvalidWellnessEvent('unknown_wellness_action');
|
|
486
|
+
return null;
|
|
487
|
+
}
|
|
488
|
+
const agentId = notificationData.agentId;
|
|
489
|
+
const eventOrgId = notificationData.orgId;
|
|
490
|
+
const sessionOrgId = sessionData?.orgId;
|
|
491
|
+
const envelopeOrgId = payload.orgId;
|
|
492
|
+
const agentSessionId = sessionData?.agentSessionId;
|
|
493
|
+
const currentOrgId = this.$webex.credentials.getOrgId();
|
|
494
|
+
if (typeof agentId !== 'string' || typeof eventOrgId !== 'string' || typeof sessionOrgId !== 'string' || typeof envelopeOrgId !== 'string' || typeof agentSessionId !== 'string' || !agentId || !eventOrgId || !sessionOrgId || !envelopeOrgId || !agentSessionId) {
|
|
495
|
+
this.trackInvalidWellnessEvent('missing_wellness_identity');
|
|
496
|
+
return null;
|
|
497
|
+
}
|
|
498
|
+
if (agentId !== this.agentConfig?.agentId || eventOrgId !== currentOrgId || sessionOrgId !== currentOrgId || envelopeOrgId !== currentOrgId) {
|
|
499
|
+
this.trackInvalidWellnessEvent('mismatched_wellness_identity');
|
|
500
|
+
return null;
|
|
501
|
+
}
|
|
502
|
+
const interactionValue = sessionData.interactionId ?? sessionData.InteractionId;
|
|
503
|
+
const actionText = notificationDetails.actionText;
|
|
504
|
+
const trackingId = payload.trackingId;
|
|
505
|
+
return {
|
|
506
|
+
agentId,
|
|
507
|
+
orgId: currentOrgId,
|
|
508
|
+
agentSessionId,
|
|
509
|
+
actionEvent: actionEvent,
|
|
510
|
+
...(typeof actionText === 'string' ? {
|
|
511
|
+
actionText
|
|
512
|
+
} : {}),
|
|
513
|
+
...(typeof interactionValue === 'string' ? {
|
|
514
|
+
interactionId: interactionValue
|
|
515
|
+
} : {}),
|
|
516
|
+
...(typeof trackingId === 'string' ? {
|
|
517
|
+
trackingId
|
|
518
|
+
} : {})
|
|
519
|
+
};
|
|
520
|
+
}
|
|
521
|
+
handleWellnessBreakWebsocketPayload(payload) {
|
|
522
|
+
if (payload.type !== _constants.WELLNESS_BREAK_HANDLER) {
|
|
523
|
+
return false;
|
|
524
|
+
}
|
|
525
|
+
const wellnessEvent = this.normalizeWellnessBreakEvent(payload);
|
|
526
|
+
if (wellnessEvent) {
|
|
527
|
+
// @ts-ignore - WebexPlugin emit is available at runtime but absent from its declaration.
|
|
528
|
+
this.emit(_types3.CC_EVENTS.WELLNESS_BREAK, wellnessEvent);
|
|
529
|
+
}
|
|
530
|
+
return true;
|
|
531
|
+
}
|
|
532
|
+
handleRTDWebsocketMessage = event => {
|
|
533
|
+
let payload;
|
|
534
|
+
try {
|
|
535
|
+
payload = JSON.parse(event);
|
|
536
|
+
} catch {
|
|
537
|
+
// TaskManager retains its existing malformed RTD message handling.
|
|
538
|
+
}
|
|
539
|
+
if ((0, _Utils.isRecord)(payload) && this.handleWellnessBreakWebsocketPayload(payload)) {
|
|
540
|
+
return;
|
|
541
|
+
}
|
|
542
|
+
this.taskManager.handleRealtimeWebsocketEvent(event);
|
|
374
543
|
};
|
|
375
544
|
|
|
376
545
|
/**
|
|
@@ -381,6 +550,7 @@ class ContactCenter extends _webexCore.WebexPlugin {
|
|
|
381
550
|
incomingTaskListener() {
|
|
382
551
|
this.taskManager.on(_types4.TASK_EVENTS.TASK_INCOMING, this.handleIncomingTask);
|
|
383
552
|
this.taskManager.on(_types4.TASK_EVENTS.TASK_HYDRATE, this.handleTaskHydrate);
|
|
553
|
+
this.taskManager.on(_types4.TASK_EVENTS.TASK_MULTI_LOGIN_HYDRATE, this.handleTaskMultiLoginHydrate);
|
|
384
554
|
this.taskManager.on(_types4.TASK_EVENTS.TASK_MERGED, this.handleTaskMerged);
|
|
385
555
|
this.taskManager.on(_types4.TASK_EVENTS.TASK_CAMPAIGN_PREVIEW_RESERVATION, this.handleCampaignPreviewReservation);
|
|
386
556
|
}
|
|
@@ -413,22 +583,25 @@ class ContactCenter extends _webexCore.WebexPlugin {
|
|
|
413
583
|
*
|
|
414
584
|
* console.log('Agent ID:', profile.agentId);
|
|
415
585
|
* console.log('Default DN:', profile.defaultDn);
|
|
416
|
-
* console.log('Teams:', profile.teams.map(t => t.
|
|
586
|
+
* console.log('Teams:', profile.teams.map(t => t.id));
|
|
417
587
|
* console.log('WebRTC Enabled:', profile.webRtcEnabled);
|
|
418
588
|
* console.log('Supported Login Options:', profile.loginVoiceOptions);
|
|
419
589
|
*
|
|
420
590
|
* // Now you can proceed with station login, state changes, etc.
|
|
421
|
-
* await cc.stationLogin({ teamId: profile.teams[0].
|
|
591
|
+
* await cc.stationLogin({ teamId: profile.teams[0].id, loginOption: 'BROWSER' });
|
|
422
592
|
* ```
|
|
423
593
|
*/
|
|
424
594
|
async register() {
|
|
425
|
-
|
|
595
|
+
this.wellnessRegistrationGeneration += 1;
|
|
596
|
+
this.wellbeingBreakIdleCode = undefined;
|
|
597
|
+
_loggerProxy.default.log('Starting CC SDK registration', {
|
|
426
598
|
module: _constants.CC_FILE,
|
|
427
599
|
method: _constants.METHODS.REGISTER
|
|
428
600
|
});
|
|
429
601
|
try {
|
|
430
602
|
this.metricsManager.timeEvent([_constants4.METRIC_EVENT_NAMES.WEBSOCKET_REGISTER_SUCCESS, _constants4.METRIC_EVENT_NAMES.WEBSOCKET_REGISTER_FAILED]);
|
|
431
603
|
this.setupEventListeners();
|
|
604
|
+
this.services.webSocketManager.on('message', this.handleWebsocketMessage);
|
|
432
605
|
const resp = await this.connectWebsocket();
|
|
433
606
|
// Ensure 'dn' is always populated from 'defaultDn'
|
|
434
607
|
resp.dn = resp.defaultDn;
|
|
@@ -440,7 +613,14 @@ class ContactCenter extends _webexCore.WebexPlugin {
|
|
|
440
613
|
module: _constants.CC_FILE,
|
|
441
614
|
method: _constants.METHODS.REGISTER
|
|
442
615
|
});
|
|
443
|
-
|
|
616
|
+
|
|
617
|
+
// Registration can silently restore a station session without emitting a
|
|
618
|
+
// relogin event. Project the active session for consumers that must
|
|
619
|
+
// recover session-scoped state after a page refresh.
|
|
620
|
+
return resp.isAgentLoggedIn && this.currentAgentSessionId ? {
|
|
621
|
+
...resp,
|
|
622
|
+
agentSessionId: this.currentAgentSessionId
|
|
623
|
+
} : resp;
|
|
444
624
|
} catch (error) {
|
|
445
625
|
this.metricsManager.trackEvent(_constants4.METRIC_EVENT_NAMES.WEBSOCKET_REGISTER_FAILED, {
|
|
446
626
|
orgId: error.orgId
|
|
@@ -487,15 +667,25 @@ class ContactCenter extends _webexCore.WebexPlugin {
|
|
|
487
667
|
*
|
|
488
668
|
*/
|
|
489
669
|
async deregister() {
|
|
670
|
+
this.wellnessRegistrationGeneration += 1;
|
|
671
|
+
this.wellbeingBreakIdleCode = undefined;
|
|
672
|
+
this.updateWellnessSession();
|
|
490
673
|
try {
|
|
491
674
|
this.metricsManager.timeEvent([_constants4.METRIC_EVENT_NAMES.WEBSOCKET_DEREGISTER_SUCCESS, _constants4.METRIC_EVENT_NAMES.WEBSOCKET_DEREGISTER_FAIL]);
|
|
675
|
+
this.taskManager.clearAISummaryState();
|
|
492
676
|
this.taskManager.off(_types4.TASK_EVENTS.TASK_INCOMING, this.handleIncomingTask);
|
|
493
677
|
this.taskManager.off(_types4.TASK_EVENTS.TASK_HYDRATE, this.handleTaskHydrate);
|
|
678
|
+
this.taskManager.off(_types4.TASK_EVENTS.TASK_MULTI_LOGIN_HYDRATE, this.handleTaskMultiLoginHydrate);
|
|
494
679
|
this.taskManager.off(_types4.TASK_EVENTS.TASK_CAMPAIGN_PREVIEW_RESERVATION, this.handleCampaignPreviewReservation);
|
|
495
680
|
this.taskManager.unregisterIncomingCallEvent();
|
|
496
681
|
this.services.webSocketManager.off('message', this.handleWebsocketMessage);
|
|
497
682
|
this.services.rtdWebSocketManager.off('message', this.handleRTDWebsocketMessage);
|
|
498
683
|
this.services.connectionService.off('connectionLost', this.handleConnectionLost);
|
|
684
|
+
const {
|
|
685
|
+
publishError: wxAppPublishError
|
|
686
|
+
} = await this.teardownWxAppLocalState({
|
|
687
|
+
clearInitFlag: true
|
|
688
|
+
});
|
|
499
689
|
if (this.agentConfig.webRtcEnabled && this.agentConfig.loginVoiceOptions.includes(_types.LoginOption.BROWSER)) {
|
|
500
690
|
if (this.$webex.internal.mercury.connected) {
|
|
501
691
|
this.$webex.internal.mercury.off('online');
|
|
@@ -512,12 +702,20 @@ class ContactCenter extends _webexCore.WebexPlugin {
|
|
|
512
702
|
if (!this.services.webSocketManager.isSocketClosed) {
|
|
513
703
|
this.services.webSocketManager.close(false, 'Unregistering the SDK');
|
|
514
704
|
}
|
|
705
|
+
if (this.services.rtdWebSocketManager && !this.services.rtdWebSocketManager.isSocketClosed) {
|
|
706
|
+
this.services.rtdWebSocketManager.close(false, 'Unregistering the SDK');
|
|
707
|
+
}
|
|
515
708
|
if (this.services.rtdWebSocketManager && !this.services.rtdWebSocketManager.isSocketClosed) {
|
|
516
709
|
this.services.rtdWebSocketManager.close(false, 'Unregistering the RTD websocket');
|
|
517
710
|
}
|
|
518
711
|
|
|
519
712
|
// Clear any cached agent configuration
|
|
713
|
+
this.wellbeingBreakIdleCode = undefined;
|
|
520
714
|
this.agentConfig = null;
|
|
715
|
+
this.updateWellnessSession();
|
|
716
|
+
if (wxAppPublishError) {
|
|
717
|
+
throw wxAppPublishError;
|
|
718
|
+
}
|
|
521
719
|
_loggerProxy.default.log('Deregistered successfully', {
|
|
522
720
|
module: _constants.CC_FILE,
|
|
523
721
|
method: _constants.METHODS.DEREGISTER
|
|
@@ -571,6 +769,12 @@ class ContactCenter extends _webexCore.WebexPlugin {
|
|
|
571
769
|
* ```
|
|
572
770
|
*/
|
|
573
771
|
async getBuddyAgents(data) {
|
|
772
|
+
const {
|
|
773
|
+
action,
|
|
774
|
+
state,
|
|
775
|
+
mediaType = 'telephony'
|
|
776
|
+
} = data;
|
|
777
|
+
const buddyAgentState = state ?? (action === 'Transfer' ? _constants2.AGENT_STATE_AVAILABLE : undefined);
|
|
574
778
|
_loggerProxy.default.info('Fetching buddy agents', {
|
|
575
779
|
module: _constants.CC_FILE,
|
|
576
780
|
method: _constants.METHODS.GET_BUDDY_AGENTS
|
|
@@ -580,13 +784,16 @@ class ContactCenter extends _webexCore.WebexPlugin {
|
|
|
580
784
|
const resp = await this.services.agent.buddyAgents({
|
|
581
785
|
data: {
|
|
582
786
|
agentProfileId: this.agentConfig.agentProfileID,
|
|
583
|
-
|
|
787
|
+
mediaType,
|
|
788
|
+
...(buddyAgentState ? {
|
|
789
|
+
state: buddyAgentState
|
|
790
|
+
} : {})
|
|
584
791
|
}
|
|
585
792
|
});
|
|
586
793
|
this.metricsManager.trackEvent(_constants4.METRIC_EVENT_NAMES.FETCH_BUDDY_AGENTS_SUCCESS, {
|
|
587
794
|
..._MetricsManager.default.getCommonTrackingFieldForAQMResponse(resp),
|
|
588
|
-
mediaType
|
|
589
|
-
buddyAgentState
|
|
795
|
+
mediaType,
|
|
796
|
+
buddyAgentState,
|
|
590
797
|
buddyAgentCount: resp.data.agentList.length
|
|
591
798
|
}, ['operational']);
|
|
592
799
|
_loggerProxy.default.log(`Successfully retrieved ${resp.data.agentList.length} buddy agents`, {
|
|
@@ -599,8 +806,8 @@ class ContactCenter extends _webexCore.WebexPlugin {
|
|
|
599
806
|
const failureResp = error.details;
|
|
600
807
|
this.metricsManager.trackEvent(_constants4.METRIC_EVENT_NAMES.FETCH_BUDDY_AGENTS_FAILED, {
|
|
601
808
|
..._MetricsManager.default.getCommonTrackingFieldForAQMResponseFailed(failureResp),
|
|
602
|
-
mediaType
|
|
603
|
-
buddyAgentState
|
|
809
|
+
mediaType,
|
|
810
|
+
buddyAgentState
|
|
604
811
|
}, ['operational']);
|
|
605
812
|
const {
|
|
606
813
|
error: detailedError
|
|
@@ -616,7 +823,7 @@ class ContactCenter extends _webexCore.WebexPlugin {
|
|
|
616
823
|
* @private
|
|
617
824
|
*/
|
|
618
825
|
async connectWebsocket() {
|
|
619
|
-
_loggerProxy.default.
|
|
826
|
+
_loggerProxy.default.log('Connecting to websocket', {
|
|
620
827
|
module: _constants.CC_FILE,
|
|
621
828
|
method: _constants.METHODS.CONNECT_WEBSOCKET
|
|
622
829
|
});
|
|
@@ -632,18 +839,42 @@ class ContactCenter extends _webexCore.WebexPlugin {
|
|
|
632
839
|
module: _constants.CC_FILE,
|
|
633
840
|
method: _constants.METHODS.CONNECT_WEBSOCKET
|
|
634
841
|
});
|
|
635
|
-
|
|
842
|
+
const configFlags = {
|
|
843
|
+
isEndTaskEnabled: this.agentConfig.isEndTaskEnabled,
|
|
844
|
+
isEndConsultEnabled: this.agentConfig.isEndConsultEnabled,
|
|
845
|
+
webRtcEnabled: this.agentConfig.webRtcEnabled,
|
|
846
|
+
autoWrapup: this.agentConfig.wrapUpData?.wrapUpProps?.autoWrapup ?? false,
|
|
847
|
+
aiFeature: this.agentConfig.aiFeature,
|
|
848
|
+
consultTransfer: {
|
|
849
|
+
allowConsultToQueue: this.agentConfig.allowConsultToQueue,
|
|
850
|
+
accessQueue: this.agentConfig.accessQueue,
|
|
851
|
+
accessEntryPoint: this.agentConfig.accessEntryPoint,
|
|
852
|
+
accessBuddyTeam: this.agentConfig.accessBuddyTeam
|
|
853
|
+
},
|
|
854
|
+
enableWxBetterTogether: this.isWxBetterTogetherEnabled(),
|
|
855
|
+
getWxAppUsersubPublished: () => this.webexCrossClientService.isAnswerCallsStateActive()
|
|
856
|
+
};
|
|
857
|
+
this.taskManager.setConfigFlags(configFlags);
|
|
636
858
|
// TODO: Make profile a singleton to make it available throughout app/sdk so we dont need to inject info everywhere
|
|
637
859
|
this.taskManager.setWrapupData(this.agentConfig.wrapUpData);
|
|
638
860
|
this.taskManager.setAgentId(this.agentConfig.agentId);
|
|
861
|
+
this.taskManager.setAgentName(this.agentConfig.agentName);
|
|
639
862
|
this.taskManager.setWebRtcEnabled(this.agentConfig.webRtcEnabled);
|
|
640
863
|
this.apiAIAssistant.setAIFeatureFlags(this.agentConfig.aiFeature);
|
|
641
|
-
|
|
864
|
+
this.wellbeingBreakIdleCode = undefined;
|
|
865
|
+
this.updateWellnessSession();
|
|
866
|
+
|
|
867
|
+
/**
|
|
868
|
+
* RTD websocket currently supports realtime transcripts and suggested responses.
|
|
869
|
+
* Extend this condition when additional AI RTD features are introduced.
|
|
870
|
+
* Wellness break notifications also arrive on this websocket.
|
|
871
|
+
*/
|
|
872
|
+
if (this.agentConfig.aiFeature?.realtimeTranscripts?.enable || this.agentConfig.aiFeature?.suggestedResponses?.enable || this.agentConfig.aiFeature?.generatedSummaries?.wrapUpSummariesEnabled === true || this.agentConfig.aiFeature?.generatedSummaries?.consultTransferSummariesEnabled === true || this.agentConfig.isWellnessBreakEnabled) {
|
|
642
873
|
_loggerProxy.default.info('Connecting to RTD websocket', {
|
|
643
874
|
module: _constants.CC_FILE,
|
|
644
875
|
method: _constants.METHODS.CONNECT_WEBSOCKET
|
|
645
876
|
});
|
|
646
|
-
|
|
877
|
+
this.services.rtdWebSocketManager.initWebSocket({
|
|
647
878
|
body: this.getConnectionConfig(),
|
|
648
879
|
resource: _constants3.RTD_SUBSCRIBE_API
|
|
649
880
|
}).then(() => {
|
|
@@ -653,13 +884,13 @@ class ContactCenter extends _webexCore.WebexPlugin {
|
|
|
653
884
|
});
|
|
654
885
|
this.services.rtdWebSocketManager.on('message', this.handleRTDWebsocketMessage);
|
|
655
886
|
}).catch(error => {
|
|
656
|
-
_loggerProxy.default.error(`Error
|
|
887
|
+
_loggerProxy.default.error(`Error connecting to RTD websocket ${error}`, {
|
|
657
888
|
module: _constants.CC_FILE,
|
|
658
889
|
method: _constants.METHODS.CONNECT_WEBSOCKET
|
|
659
890
|
});
|
|
660
891
|
});
|
|
661
892
|
}
|
|
662
|
-
if (this.agentConfig.webRtcEnabled && this.agentConfig.loginVoiceOptions.includes(_types.LoginOption.BROWSER)) {
|
|
893
|
+
if (this.agentConfig.webRtcEnabled && this.agentConfig.loginVoiceOptions.includes(_types.LoginOption.BROWSER) && !this.isWebRTCRegistrationDisabled()) {
|
|
663
894
|
try {
|
|
664
895
|
await this.$webex.internal.mercury.connect();
|
|
665
896
|
_loggerProxy.default.log('Authentication: webex.internal.mercury.connect successful', {
|
|
@@ -672,12 +903,23 @@ class ContactCenter extends _webexCore.WebexPlugin {
|
|
|
672
903
|
method: _constants.METHODS.CONNECT_WEBSOCKET
|
|
673
904
|
});
|
|
674
905
|
}
|
|
906
|
+
} else if (this.isWebRTCRegistrationDisabled()) {
|
|
907
|
+
_loggerProxy.default.info('Skipping Mobius registration because disableWebRTCRegistration is enabled', {
|
|
908
|
+
module: _constants.CC_FILE,
|
|
909
|
+
method: _constants.METHODS.CONNECT_WEBSOCKET
|
|
910
|
+
});
|
|
675
911
|
}
|
|
676
912
|
if (this.$config && this.$config.allowAutomatedRelogin) {
|
|
677
913
|
await this.silentRelogin();
|
|
914
|
+
} else {
|
|
915
|
+
_loggerProxy.default.log('Skipping silent relogin: allowAutomatedRelogin is disabled', {
|
|
916
|
+
module: _constants.CC_FILE,
|
|
917
|
+
method: _constants.METHODS.CONNECT_WEBSOCKET
|
|
918
|
+
});
|
|
678
919
|
}
|
|
679
920
|
return this.agentConfig;
|
|
680
921
|
} catch (error) {
|
|
922
|
+
this.updateWellnessSession();
|
|
681
923
|
_loggerProxy.default.error(`Error during register: ${error}`, {
|
|
682
924
|
module: _constants.CC_FILE,
|
|
683
925
|
method: _constants.METHODS.CONNECT_WEBSOCKET
|
|
@@ -715,30 +957,37 @@ class ContactCenter extends _webexCore.WebexPlugin {
|
|
|
715
957
|
* ```
|
|
716
958
|
*/
|
|
717
959
|
async stationLogin(data) {
|
|
718
|
-
|
|
960
|
+
const loggerContext = {
|
|
719
961
|
module: _constants.CC_FILE,
|
|
720
962
|
method: _constants.METHODS.STATION_LOGIN
|
|
721
|
-
}
|
|
963
|
+
};
|
|
722
964
|
try {
|
|
965
|
+
_loggerProxy.default.log(`Starting agent station login | loginOption: ${data?.loginOption} teamId: ${data?.teamId}`, loggerContext);
|
|
723
966
|
this.metricsManager.timeEvent([_constants4.METRIC_EVENT_NAMES.STATION_LOGIN_SUCCESS, _constants4.METRIC_EVENT_NAMES.STATION_LOGIN_FAILED]);
|
|
724
967
|
const dialPlanEntries = this.agentConfig?.dialPlan?.dialPlanEntity ?? [];
|
|
725
|
-
if (data.loginOption === _types.LoginOption.AGENT_DN
|
|
726
|
-
|
|
727
|
-
|
|
728
|
-
|
|
729
|
-
|
|
730
|
-
|
|
731
|
-
|
|
732
|
-
|
|
733
|
-
|
|
968
|
+
if (data.loginOption === _types.LoginOption.AGENT_DN) {
|
|
969
|
+
_loggerProxy.default.log(`Validating dial number | dialPlanEnabled: ${!!this.agentConfig?.dialPlan} | dialPlanEntryCount: ${dialPlanEntries.length}`, loggerContext);
|
|
970
|
+
if (!(0, _Utils.isValidDialNumber)(data.dialNumber, dialPlanEntries)) {
|
|
971
|
+
_loggerProxy.default.log(`Dial number validation failed | dialNumber: ${data.dialNumber} | dialPlanEntryCount: ${dialPlanEntries.length}`, loggerContext);
|
|
972
|
+
const error = new Error('INVALID_DIAL_NUMBER');
|
|
973
|
+
// @ts-ignore - adding custom key to the error object
|
|
974
|
+
error.details = {
|
|
975
|
+
data: {
|
|
976
|
+
reason: 'INVALID_DIAL_NUMBER'
|
|
977
|
+
}
|
|
978
|
+
};
|
|
979
|
+
throw error;
|
|
980
|
+
}
|
|
734
981
|
}
|
|
982
|
+
const deviceId = this.getDeviceId(data.loginOption, data.dialNumber);
|
|
735
983
|
const loginResponse = await this.services.agent.stationLogin({
|
|
736
984
|
data: {
|
|
737
|
-
|
|
985
|
+
// BROWSER DN must be webrtc-{agentId} so VPOP/RTMS do not treat a bare UUID as PSTN.
|
|
986
|
+
dialNumber: data.loginOption === _types.LoginOption.BROWSER ? deviceId : data.dialNumber,
|
|
738
987
|
teamId: data.teamId,
|
|
739
988
|
deviceType: data.loginOption,
|
|
740
989
|
isExtension: data.loginOption === _types.LoginOption.EXTENSION,
|
|
741
|
-
deviceId
|
|
990
|
+
deviceId,
|
|
742
991
|
roles: [_constants3.AGENT],
|
|
743
992
|
teamName: _constants.EMPTY_STRING,
|
|
744
993
|
siteId: _constants.EMPTY_STRING,
|
|
@@ -746,14 +995,20 @@ class ContactCenter extends _webexCore.WebexPlugin {
|
|
|
746
995
|
auxCodeId: _constants.EMPTY_STRING
|
|
747
996
|
}
|
|
748
997
|
});
|
|
749
|
-
if (this.agentConfig.webRtcEnabled && data.loginOption === _types.LoginOption.BROWSER) {
|
|
998
|
+
if (this.agentConfig.webRtcEnabled && data.loginOption === _types.LoginOption.BROWSER && !this.isWebRTCRegistrationDisabled()) {
|
|
750
999
|
await this.webCallingService.registerWebCallingLine();
|
|
1000
|
+
} else if (this.agentConfig.webRtcEnabled && data.loginOption === _types.LoginOption.BROWSER && this.isWebRTCRegistrationDisabled()) {
|
|
1001
|
+
_loggerProxy.default.info('Skipping web calling line registration because disableWebRTCRegistration is enabled', {
|
|
1002
|
+
module: _constants.CC_FILE,
|
|
1003
|
+
method: _constants.METHODS.STATION_LOGIN
|
|
1004
|
+
});
|
|
751
1005
|
}
|
|
752
1006
|
const resp = await loginResponse;
|
|
753
1007
|
const {
|
|
754
1008
|
channelsMap,
|
|
755
1009
|
...loginData
|
|
756
1010
|
} = resp.data;
|
|
1011
|
+
this.updateWellnessSession(resp.data.agentSessionId);
|
|
757
1012
|
this.agentConfig.currentTeamId = resp.data.teamId;
|
|
758
1013
|
const response = {
|
|
759
1014
|
...loginData,
|
|
@@ -766,6 +1021,13 @@ class ContactCenter extends _webexCore.WebexPlugin {
|
|
|
766
1021
|
notifsTrackingId: resp.trackingId
|
|
767
1022
|
};
|
|
768
1023
|
this.webCallingService.setLoginOption(data.loginOption);
|
|
1024
|
+
if (this.agentConfig) {
|
|
1025
|
+
this.agentConfig.deviceType = data.loginOption;
|
|
1026
|
+
if (data.loginOption === _types.LoginOption.AGENT_DN || data.loginOption === _types.LoginOption.EXTENSION) {
|
|
1027
|
+
this.agentConfig.defaultDn = data.dialNumber;
|
|
1028
|
+
this.agentConfig.dn = data.dialNumber;
|
|
1029
|
+
}
|
|
1030
|
+
}
|
|
769
1031
|
this.metricsManager.trackEvent(_constants4.METRIC_EVENT_NAMES.STATION_LOGIN_SUCCESS, {
|
|
770
1032
|
..._MetricsManager.default.getCommonTrackingFieldForAQMResponse(resp),
|
|
771
1033
|
loginType: data.loginOption,
|
|
@@ -778,6 +1040,7 @@ class ContactCenter extends _webexCore.WebexPlugin {
|
|
|
778
1040
|
method: _constants.METHODS.STATION_LOGIN,
|
|
779
1041
|
trackingId: resp.trackingId
|
|
780
1042
|
});
|
|
1043
|
+
await this.ensureWxAppPostStationLogin();
|
|
781
1044
|
return response;
|
|
782
1045
|
} catch (error) {
|
|
783
1046
|
const failure = error.details;
|
|
@@ -832,6 +1095,8 @@ class ContactCenter extends _webexCore.WebexPlugin {
|
|
|
832
1095
|
if (this.webCallingService) {
|
|
833
1096
|
this.webCallingService.deregisterWebCallingLine();
|
|
834
1097
|
}
|
|
1098
|
+
await this.teardownWxAppLocalState();
|
|
1099
|
+
this.updateWellnessSession();
|
|
835
1100
|
_loggerProxy.default.log(`Agent station logout completed successfully`, {
|
|
836
1101
|
module: _constants.CC_FILE,
|
|
837
1102
|
method: _constants.METHODS.STATION_LOGOUT,
|
|
@@ -925,7 +1190,7 @@ class ContactCenter extends _webexCore.WebexPlugin {
|
|
|
925
1190
|
this.metricsManager.trackEvent(_constants4.METRIC_EVENT_NAMES.AGENT_STATE_CHANGE_SUCCESS, {
|
|
926
1191
|
..._MetricsManager.default.getCommonTrackingFieldForAQMResponse(agentStatusResponse),
|
|
927
1192
|
requestedState: data.state,
|
|
928
|
-
teamId: this.agentConfig?.teams[0]?.
|
|
1193
|
+
teamId: this.agentConfig?.teams[0]?.id ?? _constants.EMPTY_STRING,
|
|
929
1194
|
status: agentStatusResponse.data?.status,
|
|
930
1195
|
subStatus: agentStatusResponse.data?.subStatus,
|
|
931
1196
|
auxCodeId: data.auxCodeId,
|
|
@@ -952,6 +1217,63 @@ class ContactCenter extends _webexCore.WebexPlugin {
|
|
|
952
1217
|
}
|
|
953
1218
|
}
|
|
954
1219
|
|
|
1220
|
+
/**
|
|
1221
|
+
* Returns the system-managed `WellbeingBreak` idle code for the current registration.
|
|
1222
|
+
* The value is fetched outside Desktop Profile filtering and cached until deregistration.
|
|
1223
|
+
* @returns The normalized system idle-code entity
|
|
1224
|
+
* @throws Structured Contact Center error when wellness is disabled or the code is unavailable
|
|
1225
|
+
* @example
|
|
1226
|
+
* const idleCode = await webex.cc.getWellbeingBreakIdleCode();
|
|
1227
|
+
* @public
|
|
1228
|
+
*/
|
|
1229
|
+
async getWellbeingBreakIdleCode() {
|
|
1230
|
+
const method = _constants.METHODS.GET_WELLBEING_BREAK_IDLE_CODE;
|
|
1231
|
+
try {
|
|
1232
|
+
if (!this.agentConfig?.isWellnessBreakEnabled) {
|
|
1233
|
+
const validationError = new Error('WELLNESS_BREAK_NOT_ENABLED');
|
|
1234
|
+
validationError.details = {
|
|
1235
|
+
type: 'SDK_VALIDATION_ERROR',
|
|
1236
|
+
orgId: this.$webex.credentials.getOrgId(),
|
|
1237
|
+
trackingId: _constants.EMPTY_STRING,
|
|
1238
|
+
data: {
|
|
1239
|
+
reason: 'WELLNESS_BREAK_NOT_ENABLED'
|
|
1240
|
+
}
|
|
1241
|
+
};
|
|
1242
|
+
throw validationError;
|
|
1243
|
+
}
|
|
1244
|
+
if (this.wellbeingBreakIdleCode) {
|
|
1245
|
+
return this.wellbeingBreakIdleCode;
|
|
1246
|
+
}
|
|
1247
|
+
this.metricsManager.timeEvent([_constants4.METRIC_EVENT_NAMES.WELLBEING_BREAK_IDLE_CODE_FETCH_SUCCESS, _constants4.METRIC_EVENT_NAMES.WELLBEING_BREAK_IDLE_CODE_FETCH_FAILED]);
|
|
1248
|
+
const registrationGeneration = this.wellnessRegistrationGeneration;
|
|
1249
|
+
const orgId = this.$webex.credentials.getOrgId();
|
|
1250
|
+
const idleCode = await this.services.config.getWellbeingBreakIdleCode(orgId);
|
|
1251
|
+
if (registrationGeneration !== this.wellnessRegistrationGeneration || orgId !== this.$webex.credentials.getOrgId() || !this.agentConfig?.isWellnessBreakEnabled) {
|
|
1252
|
+
const staleRegistrationError = new Error('WELLNESS_BREAK_REGISTRATION_CHANGED');
|
|
1253
|
+
staleRegistrationError.details = {
|
|
1254
|
+
type: 'SDK_VALIDATION_ERROR',
|
|
1255
|
+
orgId,
|
|
1256
|
+
trackingId: _constants.EMPTY_STRING,
|
|
1257
|
+
data: {
|
|
1258
|
+
reason: 'WELLNESS_BREAK_REGISTRATION_CHANGED'
|
|
1259
|
+
}
|
|
1260
|
+
};
|
|
1261
|
+
throw staleRegistrationError;
|
|
1262
|
+
}
|
|
1263
|
+
this.wellbeingBreakIdleCode = idleCode;
|
|
1264
|
+
this.metricsManager.trackEvent(_constants4.METRIC_EVENT_NAMES.WELLBEING_BREAK_IDLE_CODE_FETCH_SUCCESS, {}, ['operational']);
|
|
1265
|
+
return idleCode;
|
|
1266
|
+
} catch (error) {
|
|
1267
|
+
this.metricsManager.trackEvent(_constants4.METRIC_EVENT_NAMES.WELLBEING_BREAK_IDLE_CODE_FETCH_FAILED, {
|
|
1268
|
+
reason: error instanceof Error ? error.message : _constants.UNKNOWN_ERROR
|
|
1269
|
+
}, ['operational']);
|
|
1270
|
+
const {
|
|
1271
|
+
error: detailedError
|
|
1272
|
+
} = (0, _Utils.getErrorDetails)(error, method, _constants.CC_FILE);
|
|
1273
|
+
throw detailedError;
|
|
1274
|
+
}
|
|
1275
|
+
}
|
|
1276
|
+
|
|
955
1277
|
/**
|
|
956
1278
|
* Processes incoming websocket messages and emits corresponding events
|
|
957
1279
|
* Handles various event types including agent state changes, login events,
|
|
@@ -961,8 +1283,9 @@ class ContactCenter extends _webexCore.WebexPlugin {
|
|
|
961
1283
|
*/
|
|
962
1284
|
handleWebsocketMessage = event => {
|
|
963
1285
|
const eventData = JSON.parse(event);
|
|
964
|
-
// Re-emit all the events related to agent except keep-alives
|
|
965
|
-
|
|
1286
|
+
// Re-emit all the events related to agent except keep-alives. Only event names present in
|
|
1287
|
+
// the typed CC_EVENTS allow-list are emitted; unknown/server-injected types are ignored.
|
|
1288
|
+
if (!eventData.keepalive && eventData.data && eventData.data.type && CC_EVENT_ALLOW_LIST.has(eventData.data.type)) {
|
|
966
1289
|
// @ts-ignore
|
|
967
1290
|
this.emit(eventData.data.type, eventData.data);
|
|
968
1291
|
}
|
|
@@ -985,8 +1308,14 @@ class ContactCenter extends _webexCore.WebexPlugin {
|
|
|
985
1308
|
};
|
|
986
1309
|
this.metricsManager.trackEvent(_constants4.METRIC_EVENT_NAMES.WEBSOCKET_EVENT_RECEIVED, metricsPayload, ['operational']);
|
|
987
1310
|
}
|
|
1311
|
+
if (this.handleWellnessBreakWebsocketPayload(eventData)) {
|
|
1312
|
+
return;
|
|
1313
|
+
}
|
|
988
1314
|
switch (eventData.type) {
|
|
989
1315
|
case _types3.CC_EVENTS.AGENT_MULTI_LOGIN:
|
|
1316
|
+
if (eventData.data?.type === 'AgentMultiLoginCloseSession' && (!eventData.data.agentSessionId || eventData.data.agentSessionId === this.currentAgentSessionId)) {
|
|
1317
|
+
this.updateWellnessSession();
|
|
1318
|
+
}
|
|
990
1319
|
// @ts-ignore
|
|
991
1320
|
this.emit(_types2.AGENT_EVENTS.AGENT_MULTI_LOGIN, eventData.data);
|
|
992
1321
|
break;
|
|
@@ -1007,6 +1336,7 @@ class ContactCenter extends _webexCore.WebexPlugin {
|
|
|
1007
1336
|
channelsMap,
|
|
1008
1337
|
...loginData
|
|
1009
1338
|
} = eventData.data;
|
|
1339
|
+
this.updateWellnessSession(loginData.agentSessionId);
|
|
1010
1340
|
const stationLoginData = {
|
|
1011
1341
|
...loginData,
|
|
1012
1342
|
mmProfile: {
|
|
@@ -1028,6 +1358,7 @@ class ContactCenter extends _webexCore.WebexPlugin {
|
|
|
1028
1358
|
channelsMap,
|
|
1029
1359
|
...loginData
|
|
1030
1360
|
} = eventData.data;
|
|
1361
|
+
this.updateWellnessSession(loginData.agentSessionId);
|
|
1031
1362
|
const stationReLoginData = {
|
|
1032
1363
|
...loginData,
|
|
1033
1364
|
mmProfile: {
|
|
@@ -1040,8 +1371,8 @@ class ContactCenter extends _webexCore.WebexPlugin {
|
|
|
1040
1371
|
};
|
|
1041
1372
|
// @ts-ignore
|
|
1042
1373
|
this.emit(_types2.AGENT_EVENTS.AGENT_RELOGIN_SUCCESS, stationReLoginData);
|
|
1374
|
+
break;
|
|
1043
1375
|
}
|
|
1044
|
-
break;
|
|
1045
1376
|
case _types3.CC_EVENTS.AGENT_STATE_CHANGE_SUCCESS:
|
|
1046
1377
|
// @ts-ignore
|
|
1047
1378
|
this.emit(_types2.AGENT_EVENTS.AGENT_STATE_CHANGE_SUCCESS, eventData.data);
|
|
@@ -1055,6 +1386,9 @@ class ContactCenter extends _webexCore.WebexPlugin {
|
|
|
1055
1386
|
this.emit(_types2.AGENT_EVENTS.AGENT_STATION_LOGIN_FAILED, eventData.data);
|
|
1056
1387
|
break;
|
|
1057
1388
|
case _types3.CC_EVENTS.AGENT_LOGOUT_SUCCESS:
|
|
1389
|
+
if (!eventData.data.agentSessionId || eventData.data.agentSessionId === this.currentAgentSessionId) {
|
|
1390
|
+
this.updateWellnessSession();
|
|
1391
|
+
}
|
|
1058
1392
|
// @ts-ignore
|
|
1059
1393
|
this.emit(_types2.AGENT_EVENTS.AGENT_LOGOUT_SUCCESS, eventData.data);
|
|
1060
1394
|
break;
|
|
@@ -1071,6 +1405,504 @@ class ContactCenter extends _webexCore.WebexPlugin {
|
|
|
1071
1405
|
}
|
|
1072
1406
|
};
|
|
1073
1407
|
|
|
1408
|
+
/**
|
|
1409
|
+
* Checks whether Mobius/WebRTC registration should be skipped by config
|
|
1410
|
+
* @returns {boolean} True when browser WebRTC registration is disabled
|
|
1411
|
+
* @private
|
|
1412
|
+
*/
|
|
1413
|
+
isWebRTCRegistrationDisabled() {
|
|
1414
|
+
return this.$config?.disableWebRTCRegistration === true;
|
|
1415
|
+
}
|
|
1416
|
+
|
|
1417
|
+
/**
|
|
1418
|
+
* Validates contact-center plugin configuration before service initialization
|
|
1419
|
+
* @private
|
|
1420
|
+
*/
|
|
1421
|
+
validatePluginConfig() {
|
|
1422
|
+
if (this.$config?.disableWebRTCRegistration === true && this.$config?.allowMultiLogin === false) {
|
|
1423
|
+
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.');
|
|
1424
|
+
}
|
|
1425
|
+
}
|
|
1426
|
+
|
|
1427
|
+
/**
|
|
1428
|
+
* Whether wxApp thick-client answer is enabled for this SDK instance.
|
|
1429
|
+
* @public
|
|
1430
|
+
*/
|
|
1431
|
+
isWxBetterTogetherEnabled() {
|
|
1432
|
+
return this.$config?.enableWxBetterTogether === true;
|
|
1433
|
+
}
|
|
1434
|
+
|
|
1435
|
+
/**
|
|
1436
|
+
* Current station login option (Extension, Dial Number, or Browser/Desktop).
|
|
1437
|
+
* Prefer webCallingService — updated on every stationLogin before wxApp hooks run.
|
|
1438
|
+
* @private
|
|
1439
|
+
*/
|
|
1440
|
+
getCurrentStationLoginOption() {
|
|
1441
|
+
return this.webCallingService?.loginOption ?? this.agentConfig?.deviceType;
|
|
1442
|
+
}
|
|
1443
|
+
|
|
1444
|
+
/**
|
|
1445
|
+
* wxApp thick-client answer is supported for Extension and Dial Number station login only —
|
|
1446
|
+
* not Browser/Desktop (WebRTC) login.
|
|
1447
|
+
* @private
|
|
1448
|
+
*/
|
|
1449
|
+
assertWxAppStationLoginSupportedForEnable() {
|
|
1450
|
+
const loginOption = this.getCurrentStationLoginOption();
|
|
1451
|
+
if (loginOption !== _types.LoginOption.EXTENSION && loginOption !== _types.LoginOption.AGENT_DN) {
|
|
1452
|
+
throw new Error('setManageWebexCallingInWxcc requires EXTENSION or AGENT_DN station login. Complete station login before enabling.');
|
|
1453
|
+
}
|
|
1454
|
+
}
|
|
1455
|
+
|
|
1456
|
+
/**
|
|
1457
|
+
* Clears runtime wxApp config after logout/deregister so stale flags do not apply on relogin.
|
|
1458
|
+
* @private
|
|
1459
|
+
*/
|
|
1460
|
+
resetEnableWxBetterTogetherConfig() {
|
|
1461
|
+
if (this.$config) {
|
|
1462
|
+
this.$config.enableWxBetterTogether = false;
|
|
1463
|
+
}
|
|
1464
|
+
this.taskManager.applyEnableWxBetterTogether(false);
|
|
1465
|
+
}
|
|
1466
|
+
|
|
1467
|
+
/**
|
|
1468
|
+
* Runtime enable/disable for wxApp Better Together (toast suppression + Mercury mute sync).
|
|
1469
|
+
*
|
|
1470
|
+
* **Phase 1 (WXCC-6026 / MMT): NOT part of the public host contract.**
|
|
1471
|
+
* Hosts must set `webexConfig.cc.enableWxBetterTogether` before `webex.init()` / `cc.register()`.
|
|
1472
|
+
* To change the flag after the SDK is initialized, re-init the SDK with the updated config.
|
|
1473
|
+
*
|
|
1474
|
+
* **Supported public read API:** {@link isWxBetterTogetherEnabled}.
|
|
1475
|
+
* **Supported telephony API:** unified `task.accept()`, `task.decline()`, `task.toggleMute()`,
|
|
1476
|
+
* `task.transmitDtmf()` — SDK routes wxApp calls internally when the init flag is active.
|
|
1477
|
+
*
|
|
1478
|
+
* **Production lifecycle does not call this method.** Station login, silent relogin, logout,
|
|
1479
|
+
* and deregister use {@link ensureWxAppPostStationLogin} and {@link teardownWxAppLocalState}
|
|
1480
|
+
* (usersub publish + Mercury subscribe/unsubscribe based on the init flag).
|
|
1481
|
+
*
|
|
1482
|
+
* This setter remains as a **private implementation** for Phase 2 runtime toggle and unit tests.
|
|
1483
|
+
* It updates `$config.enableWxBetterTogether`, TaskManager flags, cross-client usersub
|
|
1484
|
+
* (`answer-calls-on-wxcc`), and Mercury mute sync; rolls back config on publish/connect failure.
|
|
1485
|
+
*
|
|
1486
|
+
* @param enabled - `true` to enable wxApp answer + usersub suppression; `false` to disable and tear down.
|
|
1487
|
+
* @throws When enabling without login, on unsupported BROWSER station login, or when usersub/Mercury init fails.
|
|
1488
|
+
* @internal
|
|
1489
|
+
* @see enableWxBetterTogether (CCPluginConfig init flag)
|
|
1490
|
+
* @see ensureWxAppPostStationLogin
|
|
1491
|
+
* @see teardownWxAppLocalState
|
|
1492
|
+
*/
|
|
1493
|
+
async setManageWebexCallingInWxcc(enabled) {
|
|
1494
|
+
if (enabled && !this.$webex.internal.device?.userId) {
|
|
1495
|
+
throw new Error('Cannot publish answer-calls-on-wxcc: user is not logged in');
|
|
1496
|
+
}
|
|
1497
|
+
if (enabled) {
|
|
1498
|
+
this.assertWxAppStationLoginSupportedForEnable();
|
|
1499
|
+
}
|
|
1500
|
+
const previousEnabled = this.isWxBetterTogetherEnabled();
|
|
1501
|
+
if (this.$config) {
|
|
1502
|
+
this.$config.enableWxBetterTogether = enabled;
|
|
1503
|
+
}
|
|
1504
|
+
this.taskManager.applyEnableWxBetterTogether(enabled);
|
|
1505
|
+
let publishedEnable = false;
|
|
1506
|
+
try {
|
|
1507
|
+
if (enabled) {
|
|
1508
|
+
await this.ensureWxAppMercuryAndSubscribe();
|
|
1509
|
+
await this.publishAnswerOnWebexCrossClientState(true);
|
|
1510
|
+
publishedEnable = true;
|
|
1511
|
+
this.taskManager.syncWxAppMuteFromCallDetailsForAllTasks();
|
|
1512
|
+
this.taskManager.refreshWxAppOfferObservabilityForAllTasks();
|
|
1513
|
+
} else {
|
|
1514
|
+
await this.publishAnswerOnWebexCrossClientState(false);
|
|
1515
|
+
this.wxAppTelephonyMercurySync.unsubscribe();
|
|
1516
|
+
await this.releaseWxAppMercuryResources();
|
|
1517
|
+
}
|
|
1518
|
+
} catch (error) {
|
|
1519
|
+
if (publishedEnable) {
|
|
1520
|
+
await this.revertWxAppCrossClientPublish();
|
|
1521
|
+
} else if (enabled) {
|
|
1522
|
+
this.wxAppTelephonyMercurySync.unsubscribe();
|
|
1523
|
+
await this.releaseWxAppMercuryResources();
|
|
1524
|
+
}
|
|
1525
|
+
if (this.$config) {
|
|
1526
|
+
this.$config.enableWxBetterTogether = previousEnabled;
|
|
1527
|
+
}
|
|
1528
|
+
this.taskManager.applyEnableWxBetterTogether(previousEnabled);
|
|
1529
|
+
throw error;
|
|
1530
|
+
}
|
|
1531
|
+
}
|
|
1532
|
+
getWxAppTelephonyTaskType() {
|
|
1533
|
+
const loginOption = this.getCurrentStationLoginOption();
|
|
1534
|
+
if (loginOption === _types.LoginOption.BROWSER) {
|
|
1535
|
+
return 'WebRTC';
|
|
1536
|
+
}
|
|
1537
|
+
if (loginOption === _types.LoginOption.EXTENSION || loginOption === _types.LoginOption.AGENT_DN) {
|
|
1538
|
+
return 'Voice';
|
|
1539
|
+
}
|
|
1540
|
+
return 'unknown';
|
|
1541
|
+
}
|
|
1542
|
+
async ensureWxAppPostStationLogin() {
|
|
1543
|
+
const loginOption = this.getCurrentStationLoginOption();
|
|
1544
|
+
const flagEnabled = this.isWxBetterTogetherEnabled();
|
|
1545
|
+
const telephonyTaskType = this.getWxAppTelephonyTaskType();
|
|
1546
|
+
if (loginOption === _types.LoginOption.BROWSER) {
|
|
1547
|
+
if (flagEnabled) {
|
|
1548
|
+
(0, _wxAppDiagnosticLogging.logWxAppSessionReadiness)({
|
|
1549
|
+
enableWxBetterTogether: true,
|
|
1550
|
+
loginOption,
|
|
1551
|
+
wxAppHooksApplied: false,
|
|
1552
|
+
usersubPublished: false,
|
|
1553
|
+
mercurySubscribed: false,
|
|
1554
|
+
telephonyTaskType,
|
|
1555
|
+
skipReason: 'unsupported_browser_login'
|
|
1556
|
+
});
|
|
1557
|
+
this.metricsManager.trackEvent(_constants4.METRIC_EVENT_NAMES.WXAPP_SESSION_SKIPPED, {
|
|
1558
|
+
loginOption,
|
|
1559
|
+
enableWxBetterTogether: true,
|
|
1560
|
+
skipReason: 'unsupported_browser_login'
|
|
1561
|
+
}, ['operational', 'behavioral']);
|
|
1562
|
+
}
|
|
1563
|
+
return;
|
|
1564
|
+
}
|
|
1565
|
+
let publishedEnable = false;
|
|
1566
|
+
let wxAppInitStage = 'mercury';
|
|
1567
|
+
try {
|
|
1568
|
+
if (flagEnabled) {
|
|
1569
|
+
this.metricsManager.timeEvent([_constants4.METRIC_EVENT_NAMES.WXAPP_SESSION_INIT_SUCCESS, _constants4.METRIC_EVENT_NAMES.WXAPP_SESSION_INIT_FAILED]);
|
|
1570
|
+
await this.ensureWxAppMercuryAndSubscribe();
|
|
1571
|
+
wxAppInitStage = 'publish';
|
|
1572
|
+
await this.publishAnswerOnWebexCrossClientState(true);
|
|
1573
|
+
publishedEnable = true;
|
|
1574
|
+
this.taskManager.syncWxAppMuteFromCallDetailsForAllTasks();
|
|
1575
|
+
this.taskManager.refreshWxAppOfferObservabilityForAllTasks();
|
|
1576
|
+
const mercurySubscribed = this.wxAppTelephonyMercurySync.isSubscribed();
|
|
1577
|
+
const usersubPublished = this.webexCrossClientService.isAnswerCallsStateActive();
|
|
1578
|
+
(0, _wxAppDiagnosticLogging.logWxAppSessionReadiness)({
|
|
1579
|
+
enableWxBetterTogether: true,
|
|
1580
|
+
loginOption,
|
|
1581
|
+
wxAppHooksApplied: true,
|
|
1582
|
+
usersubPublished,
|
|
1583
|
+
mercurySubscribed,
|
|
1584
|
+
telephonyTaskType
|
|
1585
|
+
});
|
|
1586
|
+
const sessionInitReady = mercurySubscribed && usersubPublished;
|
|
1587
|
+
if (sessionInitReady) {
|
|
1588
|
+
this.metricsManager.trackEvent(_constants4.METRIC_EVENT_NAMES.WXAPP_SESSION_INIT_SUCCESS, {
|
|
1589
|
+
loginOption,
|
|
1590
|
+
enableWxBetterTogether: true,
|
|
1591
|
+
usersubPublished,
|
|
1592
|
+
mercurySubscribed,
|
|
1593
|
+
telephonyTaskType
|
|
1594
|
+
}, ['operational', 'behavioral']);
|
|
1595
|
+
} else {
|
|
1596
|
+
this.metricsManager.trackEvent(_constants4.METRIC_EVENT_NAMES.WXAPP_SESSION_INIT_FAILED, {
|
|
1597
|
+
loginOption,
|
|
1598
|
+
enableWxBetterTogether: true,
|
|
1599
|
+
usersubPublished,
|
|
1600
|
+
mercurySubscribed,
|
|
1601
|
+
telephonyTaskType,
|
|
1602
|
+
skipReason: !usersubPublished ? 'usersub_not_published' : 'mercury_not_subscribed'
|
|
1603
|
+
}, ['operational', 'behavioral']);
|
|
1604
|
+
}
|
|
1605
|
+
} else {
|
|
1606
|
+
await this.ensureWxAppDeviceRegistered();
|
|
1607
|
+
await this.publishAnswerOnWebexCrossClientState(false, {
|
|
1608
|
+
force: true
|
|
1609
|
+
});
|
|
1610
|
+
this.webexCrossClientService.teardown();
|
|
1611
|
+
this.wxAppTelephonyMercurySync.unsubscribe();
|
|
1612
|
+
await this.releaseWxAppMercuryResources();
|
|
1613
|
+
(0, _wxAppDiagnosticLogging.logWxAppSessionReadiness)({
|
|
1614
|
+
enableWxBetterTogether: false,
|
|
1615
|
+
loginOption,
|
|
1616
|
+
wxAppHooksApplied: true,
|
|
1617
|
+
usersubPublished: false,
|
|
1618
|
+
mercurySubscribed: false,
|
|
1619
|
+
telephonyTaskType,
|
|
1620
|
+
skipReason: 'flag_disabled'
|
|
1621
|
+
});
|
|
1622
|
+
this.metricsManager.trackEvent(_constants4.METRIC_EVENT_NAMES.WXAPP_SESSION_SKIPPED, {
|
|
1623
|
+
loginOption,
|
|
1624
|
+
enableWxBetterTogether: false,
|
|
1625
|
+
skipReason: 'flag_disabled'
|
|
1626
|
+
}, ['operational', 'behavioral']);
|
|
1627
|
+
}
|
|
1628
|
+
} catch (error) {
|
|
1629
|
+
_loggerProxy.default.error(`Failed to initialize wxApp post-station-login: ${error}`, {
|
|
1630
|
+
module: _constants.CC_FILE,
|
|
1631
|
+
method: _constants.METHODS.STATION_LOGIN
|
|
1632
|
+
});
|
|
1633
|
+
if (flagEnabled) {
|
|
1634
|
+
const sessionInitFailureReason = wxAppInitStage === 'mercury' ? 'mercury_subscribe_failed' : 'publish_failed';
|
|
1635
|
+
this.metricsManager.trackEvent(_constants4.METRIC_EVENT_NAMES.WXAPP_SESSION_INIT_FAILED, {
|
|
1636
|
+
loginOption,
|
|
1637
|
+
enableWxBetterTogether: true,
|
|
1638
|
+
usersubPublished: this.webexCrossClientService.isAnswerCallsStateActive(),
|
|
1639
|
+
mercurySubscribed: this.wxAppTelephonyMercurySync.isSubscribed(),
|
|
1640
|
+
telephonyTaskType,
|
|
1641
|
+
skipReason: sessionInitFailureReason,
|
|
1642
|
+
error: error instanceof Error ? error.toString() : String(error)
|
|
1643
|
+
}, ['operational', 'behavioral']);
|
|
1644
|
+
(0, _wxAppDiagnosticLogging.logWxAppSessionReadiness)({
|
|
1645
|
+
enableWxBetterTogether: true,
|
|
1646
|
+
loginOption,
|
|
1647
|
+
wxAppHooksApplied: false,
|
|
1648
|
+
usersubPublished: this.webexCrossClientService.isAnswerCallsStateActive(),
|
|
1649
|
+
mercurySubscribed: this.wxAppTelephonyMercurySync.isSubscribed(),
|
|
1650
|
+
telephonyTaskType,
|
|
1651
|
+
skipReason: sessionInitFailureReason
|
|
1652
|
+
});
|
|
1653
|
+
if (publishedEnable) {
|
|
1654
|
+
await this.revertWxAppCrossClientPublish();
|
|
1655
|
+
} else {
|
|
1656
|
+
this.wxAppTelephonyMercurySync.unsubscribe();
|
|
1657
|
+
await this.releaseWxAppMercuryResources();
|
|
1658
|
+
}
|
|
1659
|
+
this.resetEnableWxBetterTogetherConfig();
|
|
1660
|
+
} else {
|
|
1661
|
+
this.scheduleForcedFalsePublishRetry();
|
|
1662
|
+
}
|
|
1663
|
+
}
|
|
1664
|
+
}
|
|
1665
|
+
clearWxAppFalsePublishRetryTimer() {
|
|
1666
|
+
if (this.wxAppFalsePublishRetryTimer) {
|
|
1667
|
+
clearTimeout(this.wxAppFalsePublishRetryTimer);
|
|
1668
|
+
this.wxAppFalsePublishRetryTimer = undefined;
|
|
1669
|
+
}
|
|
1670
|
+
}
|
|
1671
|
+
scheduleForcedFalsePublishRetry(retryAttempt = 0) {
|
|
1672
|
+
this.scheduleFalsePublishRetry(retryAttempt, {
|
|
1673
|
+
requireDisabled: true
|
|
1674
|
+
});
|
|
1675
|
+
}
|
|
1676
|
+
|
|
1677
|
+
/**
|
|
1678
|
+
* Retries compensating false publish after rollback failure, regardless of enabled flag.
|
|
1679
|
+
* @private
|
|
1680
|
+
*/
|
|
1681
|
+
scheduleCompensatingFalsePublishRetry(retryAttempt = 0) {
|
|
1682
|
+
this.scheduleFalsePublishRetry(retryAttempt);
|
|
1683
|
+
}
|
|
1684
|
+
scheduleFalsePublishRetry(retryAttempt = 0, options = {}) {
|
|
1685
|
+
if (retryAttempt >= ContactCenter.WXAPP_FALSE_PUBLISH_MAX_RETRIES) {
|
|
1686
|
+
return;
|
|
1687
|
+
}
|
|
1688
|
+
if (options?.requireDisabled && this.isWxBetterTogetherEnabled()) {
|
|
1689
|
+
return;
|
|
1690
|
+
}
|
|
1691
|
+
this.clearWxAppFalsePublishRetryTimer();
|
|
1692
|
+
this.wxAppFalsePublishRetryTimer = setTimeout(async () => {
|
|
1693
|
+
this.wxAppFalsePublishRetryTimer = undefined;
|
|
1694
|
+
if (options?.requireDisabled && this.isWxBetterTogetherEnabled()) {
|
|
1695
|
+
return;
|
|
1696
|
+
}
|
|
1697
|
+
if (!options?.requireDisabled && this.isWxBetterTogetherEnabled() && this.webexCrossClientService.isAnswerCallsStateActive()) {
|
|
1698
|
+
return;
|
|
1699
|
+
}
|
|
1700
|
+
try {
|
|
1701
|
+
await this.ensureWxAppDeviceRegistered();
|
|
1702
|
+
await this.publishAnswerOnWebexCrossClientState(false, {
|
|
1703
|
+
force: true
|
|
1704
|
+
});
|
|
1705
|
+
this.webexCrossClientService.teardown();
|
|
1706
|
+
this.wxAppTelephonyMercurySync.unsubscribe();
|
|
1707
|
+
await this.releaseWxAppMercuryResources();
|
|
1708
|
+
} catch (retryError) {
|
|
1709
|
+
_loggerProxy.default.error(`Failed to retry forced answer-calls-on-wxcc false publish: ${retryError}`, {
|
|
1710
|
+
module: _constants.CC_FILE,
|
|
1711
|
+
method: _constants.METHODS.SET_MANAGE_WEBEX_CALLING_IN_WXCC
|
|
1712
|
+
});
|
|
1713
|
+
this.scheduleFalsePublishRetry(retryAttempt + 1, options);
|
|
1714
|
+
}
|
|
1715
|
+
}, ContactCenter.WXAPP_FALSE_PUBLISH_RETRY_DELAY_MS);
|
|
1716
|
+
}
|
|
1717
|
+
|
|
1718
|
+
/**
|
|
1719
|
+
* Best-effort rollback when usersub true was published but wxApp setup did not complete.
|
|
1720
|
+
* @private
|
|
1721
|
+
*/
|
|
1722
|
+
async revertWxAppCrossClientPublish() {
|
|
1723
|
+
try {
|
|
1724
|
+
await this.publishAnswerOnWebexCrossClientState(false, {
|
|
1725
|
+
force: true
|
|
1726
|
+
});
|
|
1727
|
+
} catch (error) {
|
|
1728
|
+
_loggerProxy.default.error(`Failed to publish compensating answer-calls-on-wxcc false during wxApp rollback: ${error}`, {
|
|
1729
|
+
module: _constants.CC_FILE,
|
|
1730
|
+
method: _constants.METHODS.SET_MANAGE_WEBEX_CALLING_IN_WXCC
|
|
1731
|
+
});
|
|
1732
|
+
this.scheduleCompensatingFalsePublishRetry();
|
|
1733
|
+
}
|
|
1734
|
+
this.webexCrossClientService.teardown();
|
|
1735
|
+
this.wxAppTelephonyMercurySync.unsubscribe();
|
|
1736
|
+
await this.releaseWxAppMercuryResources();
|
|
1737
|
+
}
|
|
1738
|
+
async ensureWxAppDeviceRegistered() {
|
|
1739
|
+
const device = this.$webex.internal.device;
|
|
1740
|
+
if (device && !device.registered && device.register) {
|
|
1741
|
+
await device.register();
|
|
1742
|
+
this.wxAppDeviceRegisteredByCc = true;
|
|
1743
|
+
_loggerProxy.default.log('WxApp: device registered for cross-client publish', {
|
|
1744
|
+
module: _constants.CC_FILE,
|
|
1745
|
+
method: _constants.METHODS.ENSURE_WXAPP_MERCURY_CONNECTED
|
|
1746
|
+
});
|
|
1747
|
+
}
|
|
1748
|
+
}
|
|
1749
|
+
async ensureWxAppMercuryConnected() {
|
|
1750
|
+
const mercury = this.$webex.internal.mercury;
|
|
1751
|
+
await this.ensureWxAppDeviceRegistered();
|
|
1752
|
+
if (mercury && !mercury.connected) {
|
|
1753
|
+
await mercury.connect();
|
|
1754
|
+
this.wxAppMercuryConnectedByCc = true;
|
|
1755
|
+
_loggerProxy.default.log('WxApp mute sync: mercury connected', {
|
|
1756
|
+
module: _constants.CC_FILE,
|
|
1757
|
+
method: _constants.METHODS.ENSURE_WXAPP_MERCURY_CONNECTED
|
|
1758
|
+
});
|
|
1759
|
+
}
|
|
1760
|
+
}
|
|
1761
|
+
|
|
1762
|
+
/**
|
|
1763
|
+
* Disconnects Mercury and unregisters the device when wxApp mute sync opened them.
|
|
1764
|
+
* @private
|
|
1765
|
+
*/
|
|
1766
|
+
async releaseWxAppMercuryResources() {
|
|
1767
|
+
const mercury = this.$webex.internal.mercury;
|
|
1768
|
+
const device = this.$webex.internal.device;
|
|
1769
|
+
if (this.wxAppMercuryConnectedByCc && mercury?.connected) {
|
|
1770
|
+
try {
|
|
1771
|
+
await mercury.disconnect();
|
|
1772
|
+
this.wxAppMercuryConnectedByCc = false;
|
|
1773
|
+
_loggerProxy.default.log('WxApp mute sync: mercury disconnected', {
|
|
1774
|
+
module: _constants.CC_FILE,
|
|
1775
|
+
method: _constants.METHODS.ENSURE_WXAPP_MERCURY_CONNECTED
|
|
1776
|
+
});
|
|
1777
|
+
} catch (error) {
|
|
1778
|
+
_loggerProxy.default.error(`Failed to disconnect wxApp Mercury: ${error}`, {
|
|
1779
|
+
module: _constants.CC_FILE,
|
|
1780
|
+
method: _constants.METHODS.ENSURE_WXAPP_MERCURY_CONNECTED
|
|
1781
|
+
});
|
|
1782
|
+
}
|
|
1783
|
+
}
|
|
1784
|
+
if (this.wxAppDeviceRegisteredByCc && device?.registered && device.unregister) {
|
|
1785
|
+
try {
|
|
1786
|
+
// @ts-ignore
|
|
1787
|
+
await device.unregister();
|
|
1788
|
+
this.wxAppDeviceRegisteredByCc = false;
|
|
1789
|
+
_loggerProxy.default.log('WxApp mute sync: device unregistered', {
|
|
1790
|
+
module: _constants.CC_FILE,
|
|
1791
|
+
method: _constants.METHODS.ENSURE_WXAPP_MERCURY_CONNECTED
|
|
1792
|
+
});
|
|
1793
|
+
} catch (error) {
|
|
1794
|
+
_loggerProxy.default.error(`Failed to unregister wxApp device: ${error}`, {
|
|
1795
|
+
module: _constants.CC_FILE,
|
|
1796
|
+
method: _constants.METHODS.ENSURE_WXAPP_MERCURY_CONNECTED
|
|
1797
|
+
});
|
|
1798
|
+
}
|
|
1799
|
+
} else if (this.wxAppDeviceRegisteredByCc) {
|
|
1800
|
+
this.wxAppDeviceRegisteredByCc = false;
|
|
1801
|
+
}
|
|
1802
|
+
}
|
|
1803
|
+
|
|
1804
|
+
/**
|
|
1805
|
+
* Clears wxApp runtime state and feature-owned resources. Publish failures are logged;
|
|
1806
|
+
* optional rethrow for deregister when callers need to surface usersub errors.
|
|
1807
|
+
* @private
|
|
1808
|
+
*/
|
|
1809
|
+
async teardownWxAppLocalState(options) {
|
|
1810
|
+
this.clearWxAppFalsePublishRetryTimer();
|
|
1811
|
+
let publishError;
|
|
1812
|
+
try {
|
|
1813
|
+
const shouldForceFalsePublish = this.isWxBetterTogetherEnabled() || this.webexCrossClientService.isAnswerCallsStateActive();
|
|
1814
|
+
await this.publishAnswerOnWebexCrossClientState(false, {
|
|
1815
|
+
force: shouldForceFalsePublish
|
|
1816
|
+
});
|
|
1817
|
+
} catch (error) {
|
|
1818
|
+
publishError = error;
|
|
1819
|
+
_loggerProxy.default.error(`Failed to publish answer-calls-on-wxcc false during wxApp teardown: ${error}`, {
|
|
1820
|
+
module: _constants.CC_FILE,
|
|
1821
|
+
method: _constants.METHODS.SET_MANAGE_WEBEX_CALLING_IN_WXCC
|
|
1822
|
+
});
|
|
1823
|
+
}
|
|
1824
|
+
this.webexCrossClientService.teardown();
|
|
1825
|
+
this.wxAppTelephonyMercurySync.unsubscribe();
|
|
1826
|
+
await this.releaseWxAppMercuryResources();
|
|
1827
|
+
if (options?.clearInitFlag) {
|
|
1828
|
+
this.resetEnableWxBetterTogetherConfig();
|
|
1829
|
+
}
|
|
1830
|
+
if (publishError) {
|
|
1831
|
+
this.scheduleCompensatingFalsePublishRetry();
|
|
1832
|
+
}
|
|
1833
|
+
if (options?.rethrowPublishError && publishError) {
|
|
1834
|
+
throw publishError;
|
|
1835
|
+
}
|
|
1836
|
+
return {
|
|
1837
|
+
publishError: publishError ?? undefined
|
|
1838
|
+
};
|
|
1839
|
+
}
|
|
1840
|
+
async ensureWxAppMercuryAndSubscribe() {
|
|
1841
|
+
if (!this.isWxBetterTogetherEnabled()) {
|
|
1842
|
+
return;
|
|
1843
|
+
}
|
|
1844
|
+
if (this.getCurrentStationLoginOption() === _types.LoginOption.BROWSER) {
|
|
1845
|
+
return;
|
|
1846
|
+
}
|
|
1847
|
+
const agentId = this.agentConfig?.agentId;
|
|
1848
|
+
if (!agentId) {
|
|
1849
|
+
_loggerProxy.default.error('Cannot subscribe wxApp mute sync: agentId unavailable', {
|
|
1850
|
+
module: _constants.CC_FILE,
|
|
1851
|
+
method: _constants.METHODS.SYNC_WXAPP_MUTE_FROM_MERCURY
|
|
1852
|
+
});
|
|
1853
|
+
this.metricsManager.trackEvent(_constants4.METRIC_EVENT_NAMES.WXAPP_MERCURY_SUBSCRIBE_FAILED, {
|
|
1854
|
+
error: 'agentId unavailable',
|
|
1855
|
+
mercurySubscribed: false
|
|
1856
|
+
}, ['operational', 'behavioral']);
|
|
1857
|
+
return;
|
|
1858
|
+
}
|
|
1859
|
+
try {
|
|
1860
|
+
await this.ensureWxAppMercuryConnected();
|
|
1861
|
+
this.wxAppTelephonyMercurySync.subscribe(agentId, (callId, muted) => {
|
|
1862
|
+
this.taskManager.applyWxAppMuteStateFromSync(callId, muted);
|
|
1863
|
+
});
|
|
1864
|
+
} catch (error) {
|
|
1865
|
+
_loggerProxy.default.error(`Failed to ensure wxApp Mercury mute sync: ${error}`, {
|
|
1866
|
+
module: _constants.CC_FILE,
|
|
1867
|
+
method: _constants.METHODS.SYNC_WXAPP_MUTE_FROM_MERCURY
|
|
1868
|
+
});
|
|
1869
|
+
this.metricsManager.trackEvent(_constants4.METRIC_EVENT_NAMES.WXAPP_MERCURY_SUBSCRIBE_FAILED, {
|
|
1870
|
+
error: error instanceof Error ? error.toString() : String(error),
|
|
1871
|
+
mercurySubscribed: false
|
|
1872
|
+
}, ['operational', 'behavioral']);
|
|
1873
|
+
this.wxAppTelephonyMercurySync.unsubscribe();
|
|
1874
|
+
await this.releaseWxAppMercuryResources();
|
|
1875
|
+
throw error;
|
|
1876
|
+
}
|
|
1877
|
+
}
|
|
1878
|
+
async publishAnswerOnWebexCrossClientState(enable, options) {
|
|
1879
|
+
if (enable && !this.isWxBetterTogetherEnabled()) {
|
|
1880
|
+
return;
|
|
1881
|
+
}
|
|
1882
|
+
if (!enable && !options?.force && !this.webexCrossClientService.isAnswerCallsStateActive()) {
|
|
1883
|
+
return;
|
|
1884
|
+
}
|
|
1885
|
+
const userId = this.$webex.internal.device?.userId;
|
|
1886
|
+
if (!userId) {
|
|
1887
|
+
if (enable && this.isWxBetterTogetherEnabled()) {
|
|
1888
|
+
this.metricsManager.trackEvent(_constants4.METRIC_EVENT_NAMES.WXAPP_USERSUB_PUBLISH_FAILED, {
|
|
1889
|
+
enableWxBetterTogether: true,
|
|
1890
|
+
usersubPublished: this.webexCrossClientService.isAnswerCallsStateActive(),
|
|
1891
|
+
skipReason: 'user_id_unavailable',
|
|
1892
|
+
error: 'User ID is unavailable for cross-client publish'
|
|
1893
|
+
}, ['operational', 'behavioral']);
|
|
1894
|
+
}
|
|
1895
|
+
return;
|
|
1896
|
+
}
|
|
1897
|
+
await this.webexCrossClientService.setManageWebexCallingInWxcc(enable, {
|
|
1898
|
+
userId,
|
|
1899
|
+
trackPublishMetrics: true
|
|
1900
|
+
});
|
|
1901
|
+
if (enable) {
|
|
1902
|
+
this.clearWxAppFalsePublishRetryTimer();
|
|
1903
|
+
}
|
|
1904
|
+
}
|
|
1905
|
+
|
|
1074
1906
|
/**
|
|
1075
1907
|
* Initializes event listeners for the Contact Center service
|
|
1076
1908
|
* Sets up handlers for connection state changes and other core events
|
|
@@ -1102,13 +1934,13 @@ class ContactCenter extends _webexCore.WebexPlugin {
|
|
|
1102
1934
|
async handleConnectionLost(msg) {
|
|
1103
1935
|
if (msg.isConnectionLost) {
|
|
1104
1936
|
// TODO: Emit an event saying connection is lost
|
|
1105
|
-
_loggerProxy.default.
|
|
1937
|
+
_loggerProxy.default.log('event=handleConnectionLost | Connection lost', {
|
|
1106
1938
|
module: _constants.CC_FILE,
|
|
1107
1939
|
method: _constants.METHODS.HANDLE_CONNECTION_LOST
|
|
1108
1940
|
});
|
|
1109
1941
|
} else if (msg.isSocketReconnected) {
|
|
1110
1942
|
// TODO: Emit an event saying connection is re-estabilished
|
|
1111
|
-
_loggerProxy.default.
|
|
1943
|
+
_loggerProxy.default.log('event=handleConnectionReconnect | Connection reconnected attempting to request silent relogin', {
|
|
1112
1944
|
module: _constants.CC_FILE,
|
|
1113
1945
|
method: _constants.METHODS.HANDLE_CONNECTION_LOST
|
|
1114
1946
|
});
|
|
@@ -1123,12 +1955,13 @@ class ContactCenter extends _webexCore.WebexPlugin {
|
|
|
1123
1955
|
* @private
|
|
1124
1956
|
*/
|
|
1125
1957
|
async silentRelogin() {
|
|
1126
|
-
_loggerProxy.default.
|
|
1958
|
+
_loggerProxy.default.log('Starting silent relogin process', {
|
|
1127
1959
|
module: _constants.CC_FILE,
|
|
1128
1960
|
method: _constants.METHODS.SILENT_RELOGIN
|
|
1129
1961
|
});
|
|
1130
1962
|
try {
|
|
1131
1963
|
const reLoginResponse = await this.services.agent.reload();
|
|
1964
|
+
this.updateWellnessSession(reLoginResponse.data.agentSessionId);
|
|
1132
1965
|
const {
|
|
1133
1966
|
agentId,
|
|
1134
1967
|
lastStateChangeReason,
|
|
@@ -1145,7 +1978,7 @@ class ContactCenter extends _webexCore.WebexPlugin {
|
|
|
1145
1978
|
this.agentConfig.currentTeamId = reLoginResponse.data.teamId;
|
|
1146
1979
|
await this.handleDeviceType(deviceType, dn);
|
|
1147
1980
|
if (lastStateChangeReason === 'agent-wss-disconnect') {
|
|
1148
|
-
_loggerProxy.default.
|
|
1981
|
+
_loggerProxy.default.log('event=requestAutoStateChange | Requesting state change to available on socket reconnect', {
|
|
1149
1982
|
module: _constants.CC_FILE,
|
|
1150
1983
|
method: _constants.METHODS.SILENT_RELOGIN
|
|
1151
1984
|
});
|
|
@@ -1169,8 +2002,7 @@ class ContactCenter extends _webexCore.WebexPlugin {
|
|
|
1169
2002
|
}
|
|
1170
2003
|
this.agentConfig.lastStateAuxCodeId = auxCodeId;
|
|
1171
2004
|
this.agentConfig.isAgentLoggedIn = true;
|
|
1172
|
-
|
|
1173
|
-
this.services.webSocketManager.on('message', this.handleWebsocketMessage);
|
|
2005
|
+
await this.ensureWxAppPostStationLogin();
|
|
1174
2006
|
_loggerProxy.default.log(`Silent relogin process completed successfully with login Option: ${reLoginResponse.data.deviceType} teamId: ${reLoginResponse.data.teamId}`, {
|
|
1175
2007
|
module: _constants.CC_FILE,
|
|
1176
2008
|
method: _constants.METHODS.SILENT_RELOGIN,
|
|
@@ -1205,6 +2037,13 @@ class ContactCenter extends _webexCore.WebexPlugin {
|
|
|
1205
2037
|
this.agentConfig.deviceType = deviceType;
|
|
1206
2038
|
switch (deviceType) {
|
|
1207
2039
|
case _types.LoginOption.BROWSER:
|
|
2040
|
+
if (this.isWebRTCRegistrationDisabled()) {
|
|
2041
|
+
_loggerProxy.default.info('Skipping web calling line registration because disableWebRTCRegistration is enabled', {
|
|
2042
|
+
module: _constants.CC_FILE,
|
|
2043
|
+
method: _constants.METHODS.HANDLE_DEVICE_TYPE
|
|
2044
|
+
});
|
|
2045
|
+
break;
|
|
2046
|
+
}
|
|
1208
2047
|
try {
|
|
1209
2048
|
await this.webCallingService.registerWebCallingLine();
|
|
1210
2049
|
} catch (error) {
|
|
@@ -1780,8 +2619,8 @@ class ContactCenter extends _webexCore.WebexPlugin {
|
|
|
1780
2619
|
}
|
|
1781
2620
|
|
|
1782
2621
|
/**
|
|
1783
|
-
* Returns paginated entry points
|
|
1784
|
-
*
|
|
2622
|
+
* Returns paginated entry points using the EntryPoint service defaults.
|
|
2623
|
+
* Existing request parameters can override those defaults.
|
|
1785
2624
|
* @public
|
|
1786
2625
|
*/
|
|
1787
2626
|
async getEntryPoints(params = {}) {
|
|
@@ -1789,8 +2628,8 @@ class ContactCenter extends _webexCore.WebexPlugin {
|
|
|
1789
2628
|
}
|
|
1790
2629
|
|
|
1791
2630
|
/**
|
|
1792
|
-
* Returns paginated contact service queues
|
|
1793
|
-
*
|
|
2631
|
+
* Returns paginated contact service queues using the Queue service defaults.
|
|
2632
|
+
* Existing request parameters can override those defaults.
|
|
1794
2633
|
* @public
|
|
1795
2634
|
*/
|
|
1796
2635
|
async getQueues(params = {}) {
|