@webex/contact-center 3.12.0-next.13 → 3.12.0-next.130
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 +884 -0
- package/AGENTS.md +94 -0
- package/ai-docs/ARCHITECTURE.md +168 -0
- package/ai-docs/CONTRACTS.md +53 -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 +382 -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 +971 -42
- 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 +45 -15
- 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 +205 -0
- package/dist/metrics/behavioral-events.js.map +1 -1
- package/dist/metrics/constants.js +48 -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 +269 -9
- 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/WebexCrossClientService.js +222 -0
- package/dist/services/WebexCrossClientService.js.map +1 -0
- package/dist/services/WxAppTelephonyMercurySync.js +108 -0
- package/dist/services/WxAppTelephonyMercurySync.js.map +1 -0
- package/dist/services/config/Util.js +11 -4
- package/dist/services/config/Util.js.map +1 -1
- package/dist/services/config/constants.js +41 -7
- package/dist/services/config/constants.js.map +1 -1
- package/dist/services/config/index.js +51 -0
- package/dist/services/config/index.js.map +1 -1
- package/dist/services/config/types.js +57 -12
- package/dist/services/config/types.js.map +1 -1
- package/dist/services/core/Err.js.map +1 -1
- package/dist/services/core/Utils.js +111 -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 +28 -14
- 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 +2 -1
- 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 +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 +1172 -521
- package/dist/services/task/TaskManager.js.map +1 -1
- package/dist/services/task/TaskUtils.js +211 -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 +12 -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 +78 -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 +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 +228 -5
- package/dist/services/task/types.js.map +1 -1
- package/dist/services/task/voice/Voice.js +1485 -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 +354 -0
- package/dist/services/task/voice/wxAppVoiceMethods.js.map +1 -0
- package/dist/services/wxAppDiagnosticLogging.js +122 -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 +193 -6
- package/dist/types/config.d.ts +13 -0
- package/dist/types/constants.d.ts +29 -1
- package/dist/types/index.d.ts +35 -8
- package/dist/types/metrics/MetricsManager.d.ts +6 -0
- package/dist/types/metrics/constants.d.ts +43 -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 +56 -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/constants.d.ts +34 -5
- package/dist/types/services/config/types.d.ts +197 -12
- package/dist/types/services/core/Err.d.ts +6 -0
- package/dist/types/services/core/Utils.d.ts +35 -13
- package/dist/types/services/core/WebexRequest.d.ts +1 -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 +175 -0
- package/dist/types/services/task/TaskFactory.d.ts +13 -0
- package/dist/types/services/task/TaskUtils.d.ts +48 -2
- package/dist/types/services/task/WebexCallingUtils.d.ts +11 -0
- package/dist/types/services/task/constants.d.ts +10 -0
- package/dist/types/services/task/contact.d.ts +4 -0
- package/dist/types/services/task/dialer.d.ts +30 -0
- package/dist/types/services/task/digital/Digital.d.ts +22 -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 +680 -66
- package/dist/types/services/task/voice/Voice.d.ts +227 -0
- package/dist/types/services/task/voice/WebRTC.d.ts +53 -0
- package/dist/types/services/task/voice/wxAppVoiceMethods.d.ts +55 -0
- package/dist/types/services/wxAppDiagnosticLogging.d.ts +51 -0
- package/dist/types/services/wxAppTelephonyUtils.d.ts +5 -0
- package/dist/types/types.d.ts +205 -9
- package/dist/types/utils/PageCache.d.ts +20 -3
- package/dist/types/webex.d.ts +1 -0
- package/dist/types.js +162 -4
- 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 +1289 -112
- package/src/config.ts +13 -0
- package/src/constants.ts +29 -1
- package/src/index.ts +36 -5
- 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 +921 -0
- package/src/metrics/behavioral-events.ts +212 -0
- package/src/metrics/constants.ts +52 -4
- package/src/services/AddressBook.ts +17 -6
- package/src/services/AnswerCallOnWebexService.ts +239 -0
- package/src/services/ApiAiAssistant.ts +356 -9
- 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 +293 -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 +505 -0
- package/src/services/config/Util.ts +12 -3
- 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 +686 -0
- package/src/services/config/constants.ts +46 -6
- package/src/services/config/index.ts +65 -0
- package/src/services/config/types.ts +197 -13
- package/src/services/core/Err.ts +3 -0
- package/src/services/core/Utils.ts +127 -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 +787 -0
- package/src/services/core/aqm-reqs.ts +30 -15
- package/src/services/core/types.ts +2 -0
- package/src/services/core/websocket/WebSocketManager.ts +2 -0
- package/src/services/core/websocket/types.ts +1 -1
- package/src/services/index.ts +1 -1
- package/src/services/task/Task.ts +908 -0
- package/src/services/task/TaskFactory.ts +60 -0
- package/src/services/task/TaskManager.ts +1419 -608
- package/src/services/task/TaskUtils.ts +303 -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 +1474 -0
- package/src/services/task/constants.ts +10 -0
- package/src/services/task/contact.ts +30 -0
- package/src/services/task/dialer.ts +80 -0
- package/src/services/task/digital/Digital.ts +97 -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 +819 -70
- package/src/services/task/voice/Voice.ts +1851 -0
- package/src/services/task/voice/WebRTC.ts +191 -0
- package/src/services/task/voice/wxAppVoiceMethods.ts +516 -0
- package/src/services/wxAppDiagnosticLogging.ts +174 -0
- package/src/services/wxAppTelephonyUtils.ts +14 -0
- package/src/types.ts +262 -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 +10 -0
- package/test/unit/spec/cc.ts +2210 -119
- 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 +311 -21
- 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 +467 -0
- package/test/unit/spec/services/WxAppTelephonyMercurySync.ts +136 -0
- package/test/unit/spec/services/config/Util.ts +129 -0
- package/test/unit/spec/services/config/index.ts +97 -29
- package/test/unit/spec/services/core/Utils.ts +425 -8
- 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 +66 -40
- package/test/unit/spec/services/task/AutoWrapup.ts +63 -0
- package/test/unit/spec/services/task/Task.ts +745 -0
- package/test/unit/spec/services/task/TaskFactory.ts +99 -0
- package/test/unit/spec/services/task/TaskManager.ts +2518 -1494
- 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 +190 -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 +2061 -0
- package/test/unit/spec/services/task/voice/WebRTC.ts +235 -0
- package/test/unit/spec/services/task/voice/wxAppVoiceMethods.ts +603 -0
- package/test/unit/spec/services/wxAppDiagnosticLogging.ts +143 -0
- package/test/unit/spec/wellnessSampleUtils.ts +288 -0
- package/umd/contact-center.min.js +2 -2
- package/umd/contact-center.min.js.map +1 -1
- package/dist/services/task/index.js +0 -1525
- package/dist/services/task/index.js.map +0 -1
- package/dist/types/services/task/index.d.ts +0 -650
- package/src/services/task/index.ts +0 -1801
- package/test/unit/spec/services/task/index.ts +0 -2184
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
|
|
@@ -184,6 +189,29 @@ class ContactCenter extends _webexCore.WebexPlugin {
|
|
|
184
189
|
* @private
|
|
185
190
|
*/
|
|
186
191
|
|
|
192
|
+
/**
|
|
193
|
+
* REST telephony for wxApp thick-client answer (WXCC-6026)
|
|
194
|
+
* @private
|
|
195
|
+
*/
|
|
196
|
+
|
|
197
|
+
/**
|
|
198
|
+
* usersub cross-client state for Webex App toast suppression
|
|
199
|
+
* @private
|
|
200
|
+
*/
|
|
201
|
+
|
|
202
|
+
/**
|
|
203
|
+
* Mercury telephony mute sync for wxApp thick-client answer
|
|
204
|
+
* @private
|
|
205
|
+
*/
|
|
206
|
+
|
|
207
|
+
/** True when wxApp mute sync opened Mercury (Extension/DN-only profiles). */
|
|
208
|
+
wxAppMercuryConnectedByCc = false;
|
|
209
|
+
|
|
210
|
+
/** True when wxApp mute sync registered the Webex device. */
|
|
211
|
+
wxAppDeviceRegisteredByCc = false;
|
|
212
|
+
static WXAPP_FALSE_PUBLISH_RETRY_DELAY_MS = 30_000;
|
|
213
|
+
static WXAPP_FALSE_PUBLISH_MAX_RETRIES = 3;
|
|
214
|
+
|
|
187
215
|
/**
|
|
188
216
|
* Core service managers for Contact Center operations
|
|
189
217
|
* Includes agent, connection, and configuration services
|
|
@@ -212,6 +240,16 @@ class ContactCenter extends _webexCore.WebexPlugin {
|
|
|
212
240
|
* @private
|
|
213
241
|
*/
|
|
214
242
|
|
|
243
|
+
/** Current login/relogin session used for agent-scoped wellness validation. */
|
|
244
|
+
|
|
245
|
+
/** Registered-session cache for the system WellbeingBreak idle code. */
|
|
246
|
+
|
|
247
|
+
/** Registration generation that owns the wellness idle-code cache and in-flight lookups. */
|
|
248
|
+
wellnessRegistrationGeneration = 0;
|
|
249
|
+
updateWellnessSession(agentSessionId) {
|
|
250
|
+
this.currentAgentSessionId = agentSessionId;
|
|
251
|
+
}
|
|
252
|
+
|
|
215
253
|
/**
|
|
216
254
|
* API instance for managing Webex Contact Center entry points
|
|
217
255
|
* Provides functionality to fetch entry points with caching support
|
|
@@ -274,6 +312,36 @@ class ContactCenter extends _webexCore.WebexPlugin {
|
|
|
274
312
|
* ```
|
|
275
313
|
*/
|
|
276
314
|
|
|
315
|
+
/**
|
|
316
|
+
* API instance for managing Webex Contact Center user preferences
|
|
317
|
+
* Provides functionality to get, create, update, and delete user preferences
|
|
318
|
+
* @type {UserPreference}
|
|
319
|
+
* @public
|
|
320
|
+
* @example
|
|
321
|
+
* ```typescript
|
|
322
|
+
* const cc = webex.cc;
|
|
323
|
+
* await cc.register();
|
|
324
|
+
* await cc.stationLogin({ teamId: 'team123', loginOption: 'BROWSER' });
|
|
325
|
+
*
|
|
326
|
+
* // Get user preferences for current user
|
|
327
|
+
* const preferences = await cc.userPreference.getUserPreference();
|
|
328
|
+
*
|
|
329
|
+
* // Create new user preferences
|
|
330
|
+
* const newPrefs = await cc.userPreference.createUserPreference({
|
|
331
|
+
* userId: 'user123',
|
|
332
|
+
* preferences: { e911Reminder: true }
|
|
333
|
+
* });
|
|
334
|
+
*
|
|
335
|
+
* // Update user preferences
|
|
336
|
+
* const updatedPrefs = await cc.userPreference.updateUserPreference('user123', {
|
|
337
|
+
* preferences: { e911Reminder: false }
|
|
338
|
+
* });
|
|
339
|
+
*
|
|
340
|
+
* // Delete user preferences
|
|
341
|
+
* await cc.userPreference.deleteUserPreference('user123');
|
|
342
|
+
* ```
|
|
343
|
+
*/
|
|
344
|
+
|
|
277
345
|
/**
|
|
278
346
|
* API instance for AI Assistant operations such as transcript controls.
|
|
279
347
|
* @type {ApiAIAssistant}
|
|
@@ -301,6 +369,7 @@ class ContactCenter extends _webexCore.WebexPlugin {
|
|
|
301
369
|
this.$webex.once(_constants.READY, () => {
|
|
302
370
|
// @ts-ignore
|
|
303
371
|
this.$config = this.config;
|
|
372
|
+
this.validatePluginConfig();
|
|
304
373
|
|
|
305
374
|
/**
|
|
306
375
|
* This is used for handling the async requests by sending webex.request and wait for corresponding websocket event.
|
|
@@ -312,13 +381,20 @@ class ContactCenter extends _webexCore.WebexPlugin {
|
|
|
312
381
|
webex: this.$webex,
|
|
313
382
|
connectionConfig: this.getConnectionConfig()
|
|
314
383
|
});
|
|
315
|
-
this.services.webSocketManager.on('message', this.handleWebsocketMessage);
|
|
316
384
|
this.webCallingService = new _WebCallingService.default(this.$webex);
|
|
317
|
-
this.
|
|
385
|
+
this.answerCallOnWebexService = new _AnswerCallOnWebexService.default(this.$webex);
|
|
386
|
+
this.webexCrossClientService = new _WebexCrossClientService.default(this.$webex);
|
|
387
|
+
this.wxAppTelephonyMercurySync = new _WxAppTelephonyMercurySync.default(this.$webex);
|
|
388
|
+
this.apiAIAssistant = new _ApiAiAssistant.ApiAIAssistant(this.$webex, () => ({
|
|
389
|
+
isWellnessBreakEnabled: this.agentConfig?.isWellnessBreakEnabled === true,
|
|
390
|
+
agentId: this.agentConfig?.agentId,
|
|
391
|
+
agentSessionId: this.currentAgentSessionId
|
|
392
|
+
}));
|
|
318
393
|
this.metricsManager = _MetricsManager.default.getInstance({
|
|
319
394
|
webex: this.$webex
|
|
320
395
|
});
|
|
321
|
-
this.taskManager = _TaskManager.default.getTaskManager(this.apiAIAssistant, this.services.contact, this.webCallingService, this.services.webSocketManager);
|
|
396
|
+
this.taskManager = _TaskManager.default.getTaskManager(this.apiAIAssistant, this.services.contact, this.webCallingService, this.services.webSocketManager, this.services.rtdWebSocketManager);
|
|
397
|
+
this.taskManager.setAnswerCallOnWebexService(this.answerCallOnWebexService);
|
|
322
398
|
this.incomingTaskListener();
|
|
323
399
|
|
|
324
400
|
// Initialize API instances
|
|
@@ -326,6 +402,7 @@ class ContactCenter extends _webexCore.WebexPlugin {
|
|
|
326
402
|
this.entryPoint = new _EntryPoint.EntryPoint(this.$webex);
|
|
327
403
|
this.addressBook = new _AddressBook.AddressBook(this.$webex, () => this.agentConfig?.addressBookId);
|
|
328
404
|
this.queue = new _Queue.Queue(this.$webex);
|
|
405
|
+
this.userPreference = new _UserPreference.UserPreference(this.$webex, () => this.agentConfig?.agentId);
|
|
329
406
|
_loggerProxy.default.initialize(this.$webex.logger);
|
|
330
407
|
});
|
|
331
408
|
}
|
|
@@ -350,6 +427,16 @@ class ContactCenter extends _webexCore.WebexPlugin {
|
|
|
350
427
|
this.trigger(_types4.TASK_EVENTS.TASK_HYDRATE, task);
|
|
351
428
|
};
|
|
352
429
|
|
|
430
|
+
/**
|
|
431
|
+
* Handles multi-login hydrate events for SDK instances without Mobius registration
|
|
432
|
+
* @private
|
|
433
|
+
* @param {ITask} task The task object associated with the multi-login hydrate
|
|
434
|
+
*/
|
|
435
|
+
handleTaskMultiLoginHydrate = task => {
|
|
436
|
+
// @ts-ignore
|
|
437
|
+
this.trigger(_types4.TASK_EVENTS.TASK_MULTI_LOGIN_HYDRATE, task);
|
|
438
|
+
};
|
|
439
|
+
|
|
353
440
|
/**
|
|
354
441
|
* Handles task merged events when tasks are combined eg: EPDN merge/transfer
|
|
355
442
|
* @private
|
|
@@ -369,8 +456,74 @@ class ContactCenter extends _webexCore.WebexPlugin {
|
|
|
369
456
|
// @ts-ignore
|
|
370
457
|
this.trigger(_types4.TASK_EVENTS.TASK_CAMPAIGN_PREVIEW_RESERVATION, task);
|
|
371
458
|
};
|
|
372
|
-
|
|
373
|
-
this.
|
|
459
|
+
trackInvalidWellnessEvent(reason) {
|
|
460
|
+
this.metricsManager.trackEvent(_constants4.METRIC_EVENT_NAMES.AI_ASSISTANT_WELLNESS_EVENT_INVALID, {
|
|
461
|
+
reason
|
|
462
|
+
}, ['operational']);
|
|
463
|
+
}
|
|
464
|
+
normalizeWellnessBreakEvent(payload) {
|
|
465
|
+
if (this.agentConfig?.isWellnessBreakEnabled !== true) {
|
|
466
|
+
this.trackInvalidWellnessEvent('wellness_disabled');
|
|
467
|
+
return null;
|
|
468
|
+
}
|
|
469
|
+
const notificationData = (0, _Utils.isRecord)(payload.data) ? payload.data : null;
|
|
470
|
+
const notificationDetails = notificationData && (0, _Utils.isRecord)(notificationData.notifDetails) ? notificationData.notifDetails : null;
|
|
471
|
+
const sessionData = notificationData && (0, _Utils.isRecord)(notificationData.data) ? notificationData.data : null;
|
|
472
|
+
const actionEvent = notificationDetails?.actionEvent;
|
|
473
|
+
if (payload.type !== _constants.WELLNESS_BREAK_HANDLER || notificationData?.notifType !== _constants.WELLNESS_BREAK_HANDLER || typeof actionEvent !== 'string') {
|
|
474
|
+
this.trackInvalidWellnessEvent('malformed_wellness_event');
|
|
475
|
+
return null;
|
|
476
|
+
}
|
|
477
|
+
if (!Object.values(_types.WELLNESS_BREAK_NOTIFICATION_ACTIONS).includes(actionEvent)) {
|
|
478
|
+
this.trackInvalidWellnessEvent('unknown_wellness_action');
|
|
479
|
+
return null;
|
|
480
|
+
}
|
|
481
|
+
const agentId = notificationData.agentId;
|
|
482
|
+
const eventOrgId = notificationData.orgId;
|
|
483
|
+
const sessionOrgId = sessionData?.orgId;
|
|
484
|
+
const envelopeOrgId = payload.orgId;
|
|
485
|
+
const agentSessionId = sessionData?.agentSessionId;
|
|
486
|
+
const currentOrgId = this.$webex.credentials.getOrgId();
|
|
487
|
+
if (typeof agentId !== 'string' || typeof eventOrgId !== 'string' || typeof sessionOrgId !== 'string' || typeof envelopeOrgId !== 'string' || typeof agentSessionId !== 'string' || !agentId || !eventOrgId || !sessionOrgId || !envelopeOrgId || !agentSessionId) {
|
|
488
|
+
this.trackInvalidWellnessEvent('missing_wellness_identity');
|
|
489
|
+
return null;
|
|
490
|
+
}
|
|
491
|
+
if (agentId !== this.agentConfig?.agentId || eventOrgId !== currentOrgId || sessionOrgId !== currentOrgId || envelopeOrgId !== currentOrgId) {
|
|
492
|
+
this.trackInvalidWellnessEvent('mismatched_wellness_identity');
|
|
493
|
+
return null;
|
|
494
|
+
}
|
|
495
|
+
const interactionValue = sessionData.interactionId ?? sessionData.InteractionId;
|
|
496
|
+
const actionText = notificationDetails.actionText;
|
|
497
|
+
const trackingId = payload.trackingId;
|
|
498
|
+
return {
|
|
499
|
+
agentId,
|
|
500
|
+
orgId: currentOrgId,
|
|
501
|
+
agentSessionId,
|
|
502
|
+
actionEvent: actionEvent,
|
|
503
|
+
...(typeof actionText === 'string' ? {
|
|
504
|
+
actionText
|
|
505
|
+
} : {}),
|
|
506
|
+
...(typeof interactionValue === 'string' ? {
|
|
507
|
+
interactionId: interactionValue
|
|
508
|
+
} : {}),
|
|
509
|
+
...(typeof trackingId === 'string' ? {
|
|
510
|
+
trackingId
|
|
511
|
+
} : {})
|
|
512
|
+
};
|
|
513
|
+
}
|
|
514
|
+
handleWellnessBreakWebsocketPayload(payload) {
|
|
515
|
+
if (payload.type !== _constants.WELLNESS_BREAK_HANDLER) {
|
|
516
|
+
return false;
|
|
517
|
+
}
|
|
518
|
+
const wellnessEvent = this.normalizeWellnessBreakEvent(payload);
|
|
519
|
+
if (wellnessEvent) {
|
|
520
|
+
// @ts-ignore - WebexPlugin emit is available at runtime but absent from its declaration.
|
|
521
|
+
this.emit(_types3.CC_EVENTS.WELLNESS_BREAK, wellnessEvent);
|
|
522
|
+
}
|
|
523
|
+
return true;
|
|
524
|
+
}
|
|
525
|
+
handleRTDWebsocketMessage = event => {
|
|
526
|
+
this.taskManager.handleRealtimeWebsocketEvent(event);
|
|
374
527
|
};
|
|
375
528
|
|
|
376
529
|
/**
|
|
@@ -381,6 +534,7 @@ class ContactCenter extends _webexCore.WebexPlugin {
|
|
|
381
534
|
incomingTaskListener() {
|
|
382
535
|
this.taskManager.on(_types4.TASK_EVENTS.TASK_INCOMING, this.handleIncomingTask);
|
|
383
536
|
this.taskManager.on(_types4.TASK_EVENTS.TASK_HYDRATE, this.handleTaskHydrate);
|
|
537
|
+
this.taskManager.on(_types4.TASK_EVENTS.TASK_MULTI_LOGIN_HYDRATE, this.handleTaskMultiLoginHydrate);
|
|
384
538
|
this.taskManager.on(_types4.TASK_EVENTS.TASK_MERGED, this.handleTaskMerged);
|
|
385
539
|
this.taskManager.on(_types4.TASK_EVENTS.TASK_CAMPAIGN_PREVIEW_RESERVATION, this.handleCampaignPreviewReservation);
|
|
386
540
|
}
|
|
@@ -422,13 +576,16 @@ class ContactCenter extends _webexCore.WebexPlugin {
|
|
|
422
576
|
* ```
|
|
423
577
|
*/
|
|
424
578
|
async register() {
|
|
425
|
-
|
|
579
|
+
this.wellnessRegistrationGeneration += 1;
|
|
580
|
+
this.wellbeingBreakIdleCode = undefined;
|
|
581
|
+
_loggerProxy.default.log('Starting CC SDK registration', {
|
|
426
582
|
module: _constants.CC_FILE,
|
|
427
583
|
method: _constants.METHODS.REGISTER
|
|
428
584
|
});
|
|
429
585
|
try {
|
|
430
586
|
this.metricsManager.timeEvent([_constants4.METRIC_EVENT_NAMES.WEBSOCKET_REGISTER_SUCCESS, _constants4.METRIC_EVENT_NAMES.WEBSOCKET_REGISTER_FAILED]);
|
|
431
587
|
this.setupEventListeners();
|
|
588
|
+
this.services.webSocketManager.on('message', this.handleWebsocketMessage);
|
|
432
589
|
const resp = await this.connectWebsocket();
|
|
433
590
|
// Ensure 'dn' is always populated from 'defaultDn'
|
|
434
591
|
resp.dn = resp.defaultDn;
|
|
@@ -487,15 +644,24 @@ class ContactCenter extends _webexCore.WebexPlugin {
|
|
|
487
644
|
*
|
|
488
645
|
*/
|
|
489
646
|
async deregister() {
|
|
647
|
+
this.wellnessRegistrationGeneration += 1;
|
|
648
|
+
this.wellbeingBreakIdleCode = undefined;
|
|
649
|
+
this.updateWellnessSession();
|
|
490
650
|
try {
|
|
491
651
|
this.metricsManager.timeEvent([_constants4.METRIC_EVENT_NAMES.WEBSOCKET_DEREGISTER_SUCCESS, _constants4.METRIC_EVENT_NAMES.WEBSOCKET_DEREGISTER_FAIL]);
|
|
492
652
|
this.taskManager.off(_types4.TASK_EVENTS.TASK_INCOMING, this.handleIncomingTask);
|
|
493
653
|
this.taskManager.off(_types4.TASK_EVENTS.TASK_HYDRATE, this.handleTaskHydrate);
|
|
654
|
+
this.taskManager.off(_types4.TASK_EVENTS.TASK_MULTI_LOGIN_HYDRATE, this.handleTaskMultiLoginHydrate);
|
|
494
655
|
this.taskManager.off(_types4.TASK_EVENTS.TASK_CAMPAIGN_PREVIEW_RESERVATION, this.handleCampaignPreviewReservation);
|
|
495
656
|
this.taskManager.unregisterIncomingCallEvent();
|
|
496
657
|
this.services.webSocketManager.off('message', this.handleWebsocketMessage);
|
|
497
658
|
this.services.rtdWebSocketManager.off('message', this.handleRTDWebsocketMessage);
|
|
498
659
|
this.services.connectionService.off('connectionLost', this.handleConnectionLost);
|
|
660
|
+
const {
|
|
661
|
+
publishError: wxAppPublishError
|
|
662
|
+
} = await this.teardownWxAppLocalState({
|
|
663
|
+
clearInitFlag: true
|
|
664
|
+
});
|
|
499
665
|
if (this.agentConfig.webRtcEnabled && this.agentConfig.loginVoiceOptions.includes(_types.LoginOption.BROWSER)) {
|
|
500
666
|
if (this.$webex.internal.mercury.connected) {
|
|
501
667
|
this.$webex.internal.mercury.off('online');
|
|
@@ -512,12 +678,20 @@ class ContactCenter extends _webexCore.WebexPlugin {
|
|
|
512
678
|
if (!this.services.webSocketManager.isSocketClosed) {
|
|
513
679
|
this.services.webSocketManager.close(false, 'Unregistering the SDK');
|
|
514
680
|
}
|
|
681
|
+
if (this.services.rtdWebSocketManager && !this.services.rtdWebSocketManager.isSocketClosed) {
|
|
682
|
+
this.services.rtdWebSocketManager.close(false, 'Unregistering the SDK');
|
|
683
|
+
}
|
|
515
684
|
if (this.services.rtdWebSocketManager && !this.services.rtdWebSocketManager.isSocketClosed) {
|
|
516
685
|
this.services.rtdWebSocketManager.close(false, 'Unregistering the RTD websocket');
|
|
517
686
|
}
|
|
518
687
|
|
|
519
688
|
// Clear any cached agent configuration
|
|
689
|
+
this.wellbeingBreakIdleCode = undefined;
|
|
520
690
|
this.agentConfig = null;
|
|
691
|
+
this.updateWellnessSession();
|
|
692
|
+
if (wxAppPublishError) {
|
|
693
|
+
throw wxAppPublishError;
|
|
694
|
+
}
|
|
521
695
|
_loggerProxy.default.log('Deregistered successfully', {
|
|
522
696
|
module: _constants.CC_FILE,
|
|
523
697
|
method: _constants.METHODS.DEREGISTER
|
|
@@ -571,6 +745,12 @@ class ContactCenter extends _webexCore.WebexPlugin {
|
|
|
571
745
|
* ```
|
|
572
746
|
*/
|
|
573
747
|
async getBuddyAgents(data) {
|
|
748
|
+
const {
|
|
749
|
+
action,
|
|
750
|
+
state,
|
|
751
|
+
mediaType = 'telephony'
|
|
752
|
+
} = data;
|
|
753
|
+
const buddyAgentState = state ?? (action === 'Transfer' ? _constants2.AGENT_STATE_AVAILABLE : undefined);
|
|
574
754
|
_loggerProxy.default.info('Fetching buddy agents', {
|
|
575
755
|
module: _constants.CC_FILE,
|
|
576
756
|
method: _constants.METHODS.GET_BUDDY_AGENTS
|
|
@@ -580,13 +760,16 @@ class ContactCenter extends _webexCore.WebexPlugin {
|
|
|
580
760
|
const resp = await this.services.agent.buddyAgents({
|
|
581
761
|
data: {
|
|
582
762
|
agentProfileId: this.agentConfig.agentProfileID,
|
|
583
|
-
|
|
763
|
+
mediaType,
|
|
764
|
+
...(buddyAgentState ? {
|
|
765
|
+
state: buddyAgentState
|
|
766
|
+
} : {})
|
|
584
767
|
}
|
|
585
768
|
});
|
|
586
769
|
this.metricsManager.trackEvent(_constants4.METRIC_EVENT_NAMES.FETCH_BUDDY_AGENTS_SUCCESS, {
|
|
587
770
|
..._MetricsManager.default.getCommonTrackingFieldForAQMResponse(resp),
|
|
588
|
-
mediaType
|
|
589
|
-
buddyAgentState
|
|
771
|
+
mediaType,
|
|
772
|
+
buddyAgentState,
|
|
590
773
|
buddyAgentCount: resp.data.agentList.length
|
|
591
774
|
}, ['operational']);
|
|
592
775
|
_loggerProxy.default.log(`Successfully retrieved ${resp.data.agentList.length} buddy agents`, {
|
|
@@ -599,8 +782,8 @@ class ContactCenter extends _webexCore.WebexPlugin {
|
|
|
599
782
|
const failureResp = error.details;
|
|
600
783
|
this.metricsManager.trackEvent(_constants4.METRIC_EVENT_NAMES.FETCH_BUDDY_AGENTS_FAILED, {
|
|
601
784
|
..._MetricsManager.default.getCommonTrackingFieldForAQMResponseFailed(failureResp),
|
|
602
|
-
mediaType
|
|
603
|
-
buddyAgentState
|
|
785
|
+
mediaType,
|
|
786
|
+
buddyAgentState
|
|
604
787
|
}, ['operational']);
|
|
605
788
|
const {
|
|
606
789
|
error: detailedError
|
|
@@ -616,7 +799,7 @@ class ContactCenter extends _webexCore.WebexPlugin {
|
|
|
616
799
|
* @private
|
|
617
800
|
*/
|
|
618
801
|
async connectWebsocket() {
|
|
619
|
-
_loggerProxy.default.
|
|
802
|
+
_loggerProxy.default.log('Connecting to websocket', {
|
|
620
803
|
module: _constants.CC_FILE,
|
|
621
804
|
method: _constants.METHODS.CONNECT_WEBSOCKET
|
|
622
805
|
});
|
|
@@ -632,18 +815,39 @@ class ContactCenter extends _webexCore.WebexPlugin {
|
|
|
632
815
|
module: _constants.CC_FILE,
|
|
633
816
|
method: _constants.METHODS.CONNECT_WEBSOCKET
|
|
634
817
|
});
|
|
635
|
-
|
|
818
|
+
const configFlags = {
|
|
819
|
+
isEndTaskEnabled: this.agentConfig.isEndTaskEnabled,
|
|
820
|
+
isEndConsultEnabled: this.agentConfig.isEndConsultEnabled,
|
|
821
|
+
webRtcEnabled: this.agentConfig.webRtcEnabled,
|
|
822
|
+
autoWrapup: this.agentConfig.wrapUpData?.wrapUpProps?.autoWrapup ?? false,
|
|
823
|
+
aiFeature: this.agentConfig.aiFeature,
|
|
824
|
+
consultTransfer: {
|
|
825
|
+
allowConsultToQueue: this.agentConfig.allowConsultToQueue,
|
|
826
|
+
accessQueue: this.agentConfig.accessQueue,
|
|
827
|
+
accessEntryPoint: this.agentConfig.accessEntryPoint,
|
|
828
|
+
accessBuddyTeam: this.agentConfig.accessBuddyTeam
|
|
829
|
+
},
|
|
830
|
+
enableWxBetterTogether: this.isWxBetterTogetherEnabled()
|
|
831
|
+
};
|
|
832
|
+
this.taskManager.setConfigFlags(configFlags);
|
|
636
833
|
// TODO: Make profile a singleton to make it available throughout app/sdk so we dont need to inject info everywhere
|
|
637
834
|
this.taskManager.setWrapupData(this.agentConfig.wrapUpData);
|
|
638
835
|
this.taskManager.setAgentId(this.agentConfig.agentId);
|
|
639
836
|
this.taskManager.setWebRtcEnabled(this.agentConfig.webRtcEnabled);
|
|
640
837
|
this.apiAIAssistant.setAIFeatureFlags(this.agentConfig.aiFeature);
|
|
641
|
-
|
|
838
|
+
this.wellbeingBreakIdleCode = undefined;
|
|
839
|
+
this.updateWellnessSession();
|
|
840
|
+
|
|
841
|
+
/**
|
|
842
|
+
* RTD websocket currently supports realtime transcripts and suggested responses.
|
|
843
|
+
* Extend this condition when additional AI RTD features are introduced.
|
|
844
|
+
*/
|
|
845
|
+
if (this.agentConfig.aiFeature?.realtimeTranscripts?.enable || this.agentConfig.aiFeature?.suggestedResponses?.enable) {
|
|
642
846
|
_loggerProxy.default.info('Connecting to RTD websocket', {
|
|
643
847
|
module: _constants.CC_FILE,
|
|
644
848
|
method: _constants.METHODS.CONNECT_WEBSOCKET
|
|
645
849
|
});
|
|
646
|
-
|
|
850
|
+
this.services.rtdWebSocketManager.initWebSocket({
|
|
647
851
|
body: this.getConnectionConfig(),
|
|
648
852
|
resource: _constants3.RTD_SUBSCRIBE_API
|
|
649
853
|
}).then(() => {
|
|
@@ -653,13 +857,13 @@ class ContactCenter extends _webexCore.WebexPlugin {
|
|
|
653
857
|
});
|
|
654
858
|
this.services.rtdWebSocketManager.on('message', this.handleRTDWebsocketMessage);
|
|
655
859
|
}).catch(error => {
|
|
656
|
-
_loggerProxy.default.error(`Error
|
|
860
|
+
_loggerProxy.default.error(`Error connecting to RTD websocket ${error}`, {
|
|
657
861
|
module: _constants.CC_FILE,
|
|
658
862
|
method: _constants.METHODS.CONNECT_WEBSOCKET
|
|
659
863
|
});
|
|
660
864
|
});
|
|
661
865
|
}
|
|
662
|
-
if (this.agentConfig.webRtcEnabled && this.agentConfig.loginVoiceOptions.includes(_types.LoginOption.BROWSER)) {
|
|
866
|
+
if (this.agentConfig.webRtcEnabled && this.agentConfig.loginVoiceOptions.includes(_types.LoginOption.BROWSER) && !this.isWebRTCRegistrationDisabled()) {
|
|
663
867
|
try {
|
|
664
868
|
await this.$webex.internal.mercury.connect();
|
|
665
869
|
_loggerProxy.default.log('Authentication: webex.internal.mercury.connect successful', {
|
|
@@ -672,12 +876,23 @@ class ContactCenter extends _webexCore.WebexPlugin {
|
|
|
672
876
|
method: _constants.METHODS.CONNECT_WEBSOCKET
|
|
673
877
|
});
|
|
674
878
|
}
|
|
879
|
+
} else if (this.isWebRTCRegistrationDisabled()) {
|
|
880
|
+
_loggerProxy.default.info('Skipping Mobius registration because disableWebRTCRegistration is enabled', {
|
|
881
|
+
module: _constants.CC_FILE,
|
|
882
|
+
method: _constants.METHODS.CONNECT_WEBSOCKET
|
|
883
|
+
});
|
|
675
884
|
}
|
|
676
885
|
if (this.$config && this.$config.allowAutomatedRelogin) {
|
|
677
886
|
await this.silentRelogin();
|
|
887
|
+
} else {
|
|
888
|
+
_loggerProxy.default.log('Skipping silent relogin: allowAutomatedRelogin is disabled', {
|
|
889
|
+
module: _constants.CC_FILE,
|
|
890
|
+
method: _constants.METHODS.CONNECT_WEBSOCKET
|
|
891
|
+
});
|
|
678
892
|
}
|
|
679
893
|
return this.agentConfig;
|
|
680
894
|
} catch (error) {
|
|
895
|
+
this.updateWellnessSession();
|
|
681
896
|
_loggerProxy.default.error(`Error during register: ${error}`, {
|
|
682
897
|
module: _constants.CC_FILE,
|
|
683
898
|
method: _constants.METHODS.CONNECT_WEBSOCKET
|
|
@@ -715,30 +930,37 @@ class ContactCenter extends _webexCore.WebexPlugin {
|
|
|
715
930
|
* ```
|
|
716
931
|
*/
|
|
717
932
|
async stationLogin(data) {
|
|
718
|
-
|
|
933
|
+
const loggerContext = {
|
|
719
934
|
module: _constants.CC_FILE,
|
|
720
935
|
method: _constants.METHODS.STATION_LOGIN
|
|
721
|
-
}
|
|
936
|
+
};
|
|
722
937
|
try {
|
|
938
|
+
_loggerProxy.default.log(`Starting agent station login | loginOption: ${data?.loginOption} teamId: ${data?.teamId}`, loggerContext);
|
|
723
939
|
this.metricsManager.timeEvent([_constants4.METRIC_EVENT_NAMES.STATION_LOGIN_SUCCESS, _constants4.METRIC_EVENT_NAMES.STATION_LOGIN_FAILED]);
|
|
724
940
|
const dialPlanEntries = this.agentConfig?.dialPlan?.dialPlanEntity ?? [];
|
|
725
|
-
if (data.loginOption === _types.LoginOption.AGENT_DN
|
|
726
|
-
|
|
727
|
-
|
|
728
|
-
|
|
729
|
-
|
|
730
|
-
|
|
731
|
-
|
|
732
|
-
|
|
733
|
-
|
|
941
|
+
if (data.loginOption === _types.LoginOption.AGENT_DN) {
|
|
942
|
+
_loggerProxy.default.log(`Validating dial number | dialPlanEnabled: ${!!this.agentConfig?.dialPlan} | dialPlanEntryCount: ${dialPlanEntries.length}`, loggerContext);
|
|
943
|
+
if (!(0, _Utils.isValidDialNumber)(data.dialNumber, dialPlanEntries)) {
|
|
944
|
+
_loggerProxy.default.log(`Dial number validation failed | dialNumber: ${data.dialNumber} | dialPlanEntryCount: ${dialPlanEntries.length}`, loggerContext);
|
|
945
|
+
const error = new Error('INVALID_DIAL_NUMBER');
|
|
946
|
+
// @ts-ignore - adding custom key to the error object
|
|
947
|
+
error.details = {
|
|
948
|
+
data: {
|
|
949
|
+
reason: 'INVALID_DIAL_NUMBER'
|
|
950
|
+
}
|
|
951
|
+
};
|
|
952
|
+
throw error;
|
|
953
|
+
}
|
|
734
954
|
}
|
|
955
|
+
const deviceId = this.getDeviceId(data.loginOption, data.dialNumber);
|
|
735
956
|
const loginResponse = await this.services.agent.stationLogin({
|
|
736
957
|
data: {
|
|
737
|
-
|
|
958
|
+
// BROWSER DN must be webrtc-{agentId} so VPOP/RTMS do not treat a bare UUID as PSTN.
|
|
959
|
+
dialNumber: data.loginOption === _types.LoginOption.BROWSER ? deviceId : data.dialNumber,
|
|
738
960
|
teamId: data.teamId,
|
|
739
961
|
deviceType: data.loginOption,
|
|
740
962
|
isExtension: data.loginOption === _types.LoginOption.EXTENSION,
|
|
741
|
-
deviceId
|
|
963
|
+
deviceId,
|
|
742
964
|
roles: [_constants3.AGENT],
|
|
743
965
|
teamName: _constants.EMPTY_STRING,
|
|
744
966
|
siteId: _constants.EMPTY_STRING,
|
|
@@ -746,14 +968,20 @@ class ContactCenter extends _webexCore.WebexPlugin {
|
|
|
746
968
|
auxCodeId: _constants.EMPTY_STRING
|
|
747
969
|
}
|
|
748
970
|
});
|
|
749
|
-
if (this.agentConfig.webRtcEnabled && data.loginOption === _types.LoginOption.BROWSER) {
|
|
971
|
+
if (this.agentConfig.webRtcEnabled && data.loginOption === _types.LoginOption.BROWSER && !this.isWebRTCRegistrationDisabled()) {
|
|
750
972
|
await this.webCallingService.registerWebCallingLine();
|
|
973
|
+
} else if (this.agentConfig.webRtcEnabled && data.loginOption === _types.LoginOption.BROWSER && this.isWebRTCRegistrationDisabled()) {
|
|
974
|
+
_loggerProxy.default.info('Skipping web calling line registration because disableWebRTCRegistration is enabled', {
|
|
975
|
+
module: _constants.CC_FILE,
|
|
976
|
+
method: _constants.METHODS.STATION_LOGIN
|
|
977
|
+
});
|
|
751
978
|
}
|
|
752
979
|
const resp = await loginResponse;
|
|
753
980
|
const {
|
|
754
981
|
channelsMap,
|
|
755
982
|
...loginData
|
|
756
983
|
} = resp.data;
|
|
984
|
+
this.updateWellnessSession(resp.data.agentSessionId);
|
|
757
985
|
this.agentConfig.currentTeamId = resp.data.teamId;
|
|
758
986
|
const response = {
|
|
759
987
|
...loginData,
|
|
@@ -766,6 +994,13 @@ class ContactCenter extends _webexCore.WebexPlugin {
|
|
|
766
994
|
notifsTrackingId: resp.trackingId
|
|
767
995
|
};
|
|
768
996
|
this.webCallingService.setLoginOption(data.loginOption);
|
|
997
|
+
if (this.agentConfig) {
|
|
998
|
+
this.agentConfig.deviceType = data.loginOption;
|
|
999
|
+
if (data.loginOption === _types.LoginOption.AGENT_DN || data.loginOption === _types.LoginOption.EXTENSION) {
|
|
1000
|
+
this.agentConfig.defaultDn = data.dialNumber;
|
|
1001
|
+
this.agentConfig.dn = data.dialNumber;
|
|
1002
|
+
}
|
|
1003
|
+
}
|
|
769
1004
|
this.metricsManager.trackEvent(_constants4.METRIC_EVENT_NAMES.STATION_LOGIN_SUCCESS, {
|
|
770
1005
|
..._MetricsManager.default.getCommonTrackingFieldForAQMResponse(resp),
|
|
771
1006
|
loginType: data.loginOption,
|
|
@@ -778,6 +1013,7 @@ class ContactCenter extends _webexCore.WebexPlugin {
|
|
|
778
1013
|
method: _constants.METHODS.STATION_LOGIN,
|
|
779
1014
|
trackingId: resp.trackingId
|
|
780
1015
|
});
|
|
1016
|
+
await this.ensureWxAppPostStationLogin();
|
|
781
1017
|
return response;
|
|
782
1018
|
} catch (error) {
|
|
783
1019
|
const failure = error.details;
|
|
@@ -832,6 +1068,8 @@ class ContactCenter extends _webexCore.WebexPlugin {
|
|
|
832
1068
|
if (this.webCallingService) {
|
|
833
1069
|
this.webCallingService.deregisterWebCallingLine();
|
|
834
1070
|
}
|
|
1071
|
+
await this.teardownWxAppLocalState();
|
|
1072
|
+
this.updateWellnessSession();
|
|
835
1073
|
_loggerProxy.default.log(`Agent station logout completed successfully`, {
|
|
836
1074
|
module: _constants.CC_FILE,
|
|
837
1075
|
method: _constants.METHODS.STATION_LOGOUT,
|
|
@@ -952,6 +1190,63 @@ class ContactCenter extends _webexCore.WebexPlugin {
|
|
|
952
1190
|
}
|
|
953
1191
|
}
|
|
954
1192
|
|
|
1193
|
+
/**
|
|
1194
|
+
* Returns the system-managed `WellbeingBreak` idle code for the current registration.
|
|
1195
|
+
* The value is fetched outside Desktop Profile filtering and cached until deregistration.
|
|
1196
|
+
* @returns The normalized system idle-code entity
|
|
1197
|
+
* @throws Structured Contact Center error when wellness is disabled or the code is unavailable
|
|
1198
|
+
* @example
|
|
1199
|
+
* const idleCode = await webex.cc.getWellbeingBreakIdleCode();
|
|
1200
|
+
* @public
|
|
1201
|
+
*/
|
|
1202
|
+
async getWellbeingBreakIdleCode() {
|
|
1203
|
+
const method = _constants.METHODS.GET_WELLBEING_BREAK_IDLE_CODE;
|
|
1204
|
+
try {
|
|
1205
|
+
if (!this.agentConfig?.isWellnessBreakEnabled) {
|
|
1206
|
+
const validationError = new Error('WELLNESS_BREAK_NOT_ENABLED');
|
|
1207
|
+
validationError.details = {
|
|
1208
|
+
type: 'SDK_VALIDATION_ERROR',
|
|
1209
|
+
orgId: this.$webex.credentials.getOrgId(),
|
|
1210
|
+
trackingId: _constants.EMPTY_STRING,
|
|
1211
|
+
data: {
|
|
1212
|
+
reason: 'WELLNESS_BREAK_NOT_ENABLED'
|
|
1213
|
+
}
|
|
1214
|
+
};
|
|
1215
|
+
throw validationError;
|
|
1216
|
+
}
|
|
1217
|
+
if (this.wellbeingBreakIdleCode) {
|
|
1218
|
+
return this.wellbeingBreakIdleCode;
|
|
1219
|
+
}
|
|
1220
|
+
this.metricsManager.timeEvent([_constants4.METRIC_EVENT_NAMES.WELLBEING_BREAK_IDLE_CODE_FETCH_SUCCESS, _constants4.METRIC_EVENT_NAMES.WELLBEING_BREAK_IDLE_CODE_FETCH_FAILED]);
|
|
1221
|
+
const registrationGeneration = this.wellnessRegistrationGeneration;
|
|
1222
|
+
const orgId = this.$webex.credentials.getOrgId();
|
|
1223
|
+
const idleCode = await this.services.config.getWellbeingBreakIdleCode(orgId);
|
|
1224
|
+
if (registrationGeneration !== this.wellnessRegistrationGeneration || orgId !== this.$webex.credentials.getOrgId() || !this.agentConfig?.isWellnessBreakEnabled) {
|
|
1225
|
+
const staleRegistrationError = new Error('WELLNESS_BREAK_REGISTRATION_CHANGED');
|
|
1226
|
+
staleRegistrationError.details = {
|
|
1227
|
+
type: 'SDK_VALIDATION_ERROR',
|
|
1228
|
+
orgId,
|
|
1229
|
+
trackingId: _constants.EMPTY_STRING,
|
|
1230
|
+
data: {
|
|
1231
|
+
reason: 'WELLNESS_BREAK_REGISTRATION_CHANGED'
|
|
1232
|
+
}
|
|
1233
|
+
};
|
|
1234
|
+
throw staleRegistrationError;
|
|
1235
|
+
}
|
|
1236
|
+
this.wellbeingBreakIdleCode = idleCode;
|
|
1237
|
+
this.metricsManager.trackEvent(_constants4.METRIC_EVENT_NAMES.WELLBEING_BREAK_IDLE_CODE_FETCH_SUCCESS, {}, ['operational']);
|
|
1238
|
+
return idleCode;
|
|
1239
|
+
} catch (error) {
|
|
1240
|
+
this.metricsManager.trackEvent(_constants4.METRIC_EVENT_NAMES.WELLBEING_BREAK_IDLE_CODE_FETCH_FAILED, {
|
|
1241
|
+
reason: error instanceof Error ? error.message : _constants.UNKNOWN_ERROR
|
|
1242
|
+
}, ['operational']);
|
|
1243
|
+
const {
|
|
1244
|
+
error: detailedError
|
|
1245
|
+
} = (0, _Utils.getErrorDetails)(error, method, _constants.CC_FILE);
|
|
1246
|
+
throw detailedError;
|
|
1247
|
+
}
|
|
1248
|
+
}
|
|
1249
|
+
|
|
955
1250
|
/**
|
|
956
1251
|
* Processes incoming websocket messages and emits corresponding events
|
|
957
1252
|
* Handles various event types including agent state changes, login events,
|
|
@@ -985,8 +1280,14 @@ class ContactCenter extends _webexCore.WebexPlugin {
|
|
|
985
1280
|
};
|
|
986
1281
|
this.metricsManager.trackEvent(_constants4.METRIC_EVENT_NAMES.WEBSOCKET_EVENT_RECEIVED, metricsPayload, ['operational']);
|
|
987
1282
|
}
|
|
1283
|
+
if (this.handleWellnessBreakWebsocketPayload(eventData)) {
|
|
1284
|
+
return;
|
|
1285
|
+
}
|
|
988
1286
|
switch (eventData.type) {
|
|
989
1287
|
case _types3.CC_EVENTS.AGENT_MULTI_LOGIN:
|
|
1288
|
+
if (eventData.data?.type === 'AgentMultiLoginCloseSession' && (!eventData.data.agentSessionId || eventData.data.agentSessionId === this.currentAgentSessionId)) {
|
|
1289
|
+
this.updateWellnessSession();
|
|
1290
|
+
}
|
|
990
1291
|
// @ts-ignore
|
|
991
1292
|
this.emit(_types2.AGENT_EVENTS.AGENT_MULTI_LOGIN, eventData.data);
|
|
992
1293
|
break;
|
|
@@ -1007,6 +1308,7 @@ class ContactCenter extends _webexCore.WebexPlugin {
|
|
|
1007
1308
|
channelsMap,
|
|
1008
1309
|
...loginData
|
|
1009
1310
|
} = eventData.data;
|
|
1311
|
+
this.updateWellnessSession(loginData.agentSessionId);
|
|
1010
1312
|
const stationLoginData = {
|
|
1011
1313
|
...loginData,
|
|
1012
1314
|
mmProfile: {
|
|
@@ -1028,6 +1330,7 @@ class ContactCenter extends _webexCore.WebexPlugin {
|
|
|
1028
1330
|
channelsMap,
|
|
1029
1331
|
...loginData
|
|
1030
1332
|
} = eventData.data;
|
|
1333
|
+
this.updateWellnessSession(loginData.agentSessionId);
|
|
1031
1334
|
const stationReLoginData = {
|
|
1032
1335
|
...loginData,
|
|
1033
1336
|
mmProfile: {
|
|
@@ -1040,8 +1343,8 @@ class ContactCenter extends _webexCore.WebexPlugin {
|
|
|
1040
1343
|
};
|
|
1041
1344
|
// @ts-ignore
|
|
1042
1345
|
this.emit(_types2.AGENT_EVENTS.AGENT_RELOGIN_SUCCESS, stationReLoginData);
|
|
1346
|
+
break;
|
|
1043
1347
|
}
|
|
1044
|
-
break;
|
|
1045
1348
|
case _types3.CC_EVENTS.AGENT_STATE_CHANGE_SUCCESS:
|
|
1046
1349
|
// @ts-ignore
|
|
1047
1350
|
this.emit(_types2.AGENT_EVENTS.AGENT_STATE_CHANGE_SUCCESS, eventData.data);
|
|
@@ -1055,6 +1358,9 @@ class ContactCenter extends _webexCore.WebexPlugin {
|
|
|
1055
1358
|
this.emit(_types2.AGENT_EVENTS.AGENT_STATION_LOGIN_FAILED, eventData.data);
|
|
1056
1359
|
break;
|
|
1057
1360
|
case _types3.CC_EVENTS.AGENT_LOGOUT_SUCCESS:
|
|
1361
|
+
if (!eventData.data.agentSessionId || eventData.data.agentSessionId === this.currentAgentSessionId) {
|
|
1362
|
+
this.updateWellnessSession();
|
|
1363
|
+
}
|
|
1058
1364
|
// @ts-ignore
|
|
1059
1365
|
this.emit(_types2.AGENT_EVENTS.AGENT_LOGOUT_SUCCESS, eventData.data);
|
|
1060
1366
|
break;
|
|
@@ -1071,6 +1377,490 @@ class ContactCenter extends _webexCore.WebexPlugin {
|
|
|
1071
1377
|
}
|
|
1072
1378
|
};
|
|
1073
1379
|
|
|
1380
|
+
/**
|
|
1381
|
+
* Checks whether Mobius/WebRTC registration should be skipped by config
|
|
1382
|
+
* @returns {boolean} True when browser WebRTC registration is disabled
|
|
1383
|
+
* @private
|
|
1384
|
+
*/
|
|
1385
|
+
isWebRTCRegistrationDisabled() {
|
|
1386
|
+
return this.$config?.disableWebRTCRegistration === true;
|
|
1387
|
+
}
|
|
1388
|
+
|
|
1389
|
+
/**
|
|
1390
|
+
* Validates contact-center plugin configuration before service initialization
|
|
1391
|
+
* @private
|
|
1392
|
+
*/
|
|
1393
|
+
validatePluginConfig() {
|
|
1394
|
+
if (this.$config?.disableWebRTCRegistration === true && this.$config?.allowMultiLogin === false) {
|
|
1395
|
+
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.');
|
|
1396
|
+
}
|
|
1397
|
+
}
|
|
1398
|
+
|
|
1399
|
+
/**
|
|
1400
|
+
* Whether wxApp thick-client answer is enabled for this SDK instance.
|
|
1401
|
+
* @public
|
|
1402
|
+
*/
|
|
1403
|
+
isWxBetterTogetherEnabled() {
|
|
1404
|
+
return this.$config?.enableWxBetterTogether === true;
|
|
1405
|
+
}
|
|
1406
|
+
|
|
1407
|
+
/**
|
|
1408
|
+
* Current station login option (Extension, Dial Number, or Browser/Desktop).
|
|
1409
|
+
* Prefer webCallingService — updated on every stationLogin before wxApp hooks run.
|
|
1410
|
+
* @private
|
|
1411
|
+
*/
|
|
1412
|
+
getCurrentStationLoginOption() {
|
|
1413
|
+
return this.webCallingService?.loginOption ?? this.agentConfig?.deviceType;
|
|
1414
|
+
}
|
|
1415
|
+
|
|
1416
|
+
/**
|
|
1417
|
+
* wxApp thick-client answer is supported for Extension and Dial Number station login only —
|
|
1418
|
+
* not Browser/Desktop (WebRTC) login.
|
|
1419
|
+
* @private
|
|
1420
|
+
*/
|
|
1421
|
+
assertWxAppStationLoginSupportedForEnable() {
|
|
1422
|
+
const loginOption = this.getCurrentStationLoginOption();
|
|
1423
|
+
if (loginOption !== _types.LoginOption.EXTENSION && loginOption !== _types.LoginOption.AGENT_DN) {
|
|
1424
|
+
throw new Error('setManageWebexCallingInWxcc requires EXTENSION or AGENT_DN station login. Complete station login before enabling.');
|
|
1425
|
+
}
|
|
1426
|
+
}
|
|
1427
|
+
|
|
1428
|
+
/**
|
|
1429
|
+
* Clears runtime wxApp config after logout/deregister so stale flags do not apply on relogin.
|
|
1430
|
+
* @private
|
|
1431
|
+
*/
|
|
1432
|
+
resetEnableWxBetterTogetherConfig() {
|
|
1433
|
+
if (this.$config) {
|
|
1434
|
+
this.$config.enableWxBetterTogether = false;
|
|
1435
|
+
}
|
|
1436
|
+
this.taskManager.applyEnableWxBetterTogether(false);
|
|
1437
|
+
}
|
|
1438
|
+
|
|
1439
|
+
/**
|
|
1440
|
+
* Runtime enable/disable for wxApp Better Together (toast suppression + Mercury mute sync).
|
|
1441
|
+
*
|
|
1442
|
+
* **Phase 1 (WXCC-6026 / MMT): NOT part of the public host contract.**
|
|
1443
|
+
* Hosts must set `webexConfig.cc.enableWxBetterTogether` before `webex.init()` / `cc.register()`.
|
|
1444
|
+
* To change the flag after the SDK is initialized, re-init the SDK with the updated config.
|
|
1445
|
+
*
|
|
1446
|
+
* **Supported public read API:** {@link isWxBetterTogetherEnabled}.
|
|
1447
|
+
* **Supported telephony API:** unified `task.accept()`, `task.decline()`, `task.toggleMute()`,
|
|
1448
|
+
* `task.transmitDtmf()` — SDK routes wxApp calls internally when the init flag is active.
|
|
1449
|
+
*
|
|
1450
|
+
* **Production lifecycle does not call this method.** Station login, silent relogin, logout,
|
|
1451
|
+
* and deregister use {@link ensureWxAppPostStationLogin} and {@link teardownWxAppLocalState}
|
|
1452
|
+
* (usersub publish + Mercury subscribe/unsubscribe based on the init flag).
|
|
1453
|
+
*
|
|
1454
|
+
* This setter remains as a **private implementation** for Phase 2 runtime toggle and unit tests.
|
|
1455
|
+
* It updates `$config.enableWxBetterTogether`, TaskManager flags, cross-client usersub
|
|
1456
|
+
* (`answer-calls-on-wxcc`), and Mercury mute sync; rolls back config on publish/connect failure.
|
|
1457
|
+
*
|
|
1458
|
+
* @param enabled - `true` to enable wxApp answer + usersub suppression; `false` to disable and tear down.
|
|
1459
|
+
* @throws When enabling without login, on unsupported BROWSER station login, or when usersub/Mercury init fails.
|
|
1460
|
+
* @internal
|
|
1461
|
+
* @see enableWxBetterTogether (CCPluginConfig init flag)
|
|
1462
|
+
* @see ensureWxAppPostStationLogin
|
|
1463
|
+
* @see teardownWxAppLocalState
|
|
1464
|
+
*/
|
|
1465
|
+
async setManageWebexCallingInWxcc(enabled) {
|
|
1466
|
+
if (enabled && !this.$webex.internal.device?.userId) {
|
|
1467
|
+
throw new Error('Cannot publish answer-calls-on-wxcc: user is not logged in');
|
|
1468
|
+
}
|
|
1469
|
+
if (enabled) {
|
|
1470
|
+
this.assertWxAppStationLoginSupportedForEnable();
|
|
1471
|
+
}
|
|
1472
|
+
const previousEnabled = this.isWxBetterTogetherEnabled();
|
|
1473
|
+
if (this.$config) {
|
|
1474
|
+
this.$config.enableWxBetterTogether = enabled;
|
|
1475
|
+
}
|
|
1476
|
+
this.taskManager.applyEnableWxBetterTogether(enabled);
|
|
1477
|
+
let publishedEnable = false;
|
|
1478
|
+
try {
|
|
1479
|
+
if (enabled) {
|
|
1480
|
+
await this.ensureWxAppMercuryAndSubscribe();
|
|
1481
|
+
await this.publishAnswerOnWebexCrossClientState(true);
|
|
1482
|
+
publishedEnable = true;
|
|
1483
|
+
this.taskManager.syncWxAppMuteFromCallDetailsForAllTasks();
|
|
1484
|
+
} else {
|
|
1485
|
+
await this.publishAnswerOnWebexCrossClientState(false);
|
|
1486
|
+
this.wxAppTelephonyMercurySync.unsubscribe();
|
|
1487
|
+
await this.releaseWxAppMercuryResources();
|
|
1488
|
+
}
|
|
1489
|
+
} catch (error) {
|
|
1490
|
+
if (publishedEnable) {
|
|
1491
|
+
await this.revertWxAppCrossClientPublish();
|
|
1492
|
+
} else if (enabled) {
|
|
1493
|
+
this.wxAppTelephonyMercurySync.unsubscribe();
|
|
1494
|
+
await this.releaseWxAppMercuryResources();
|
|
1495
|
+
}
|
|
1496
|
+
if (this.$config) {
|
|
1497
|
+
this.$config.enableWxBetterTogether = previousEnabled;
|
|
1498
|
+
}
|
|
1499
|
+
this.taskManager.applyEnableWxBetterTogether(previousEnabled);
|
|
1500
|
+
throw error;
|
|
1501
|
+
}
|
|
1502
|
+
}
|
|
1503
|
+
getWxAppTelephonyTaskType() {
|
|
1504
|
+
const loginOption = this.getCurrentStationLoginOption();
|
|
1505
|
+
if (loginOption === _types.LoginOption.BROWSER) {
|
|
1506
|
+
return 'WebRTC';
|
|
1507
|
+
}
|
|
1508
|
+
if (loginOption === _types.LoginOption.EXTENSION || loginOption === _types.LoginOption.AGENT_DN) {
|
|
1509
|
+
return 'Voice';
|
|
1510
|
+
}
|
|
1511
|
+
return 'unknown';
|
|
1512
|
+
}
|
|
1513
|
+
async ensureWxAppPostStationLogin() {
|
|
1514
|
+
const loginOption = this.getCurrentStationLoginOption();
|
|
1515
|
+
const flagEnabled = this.isWxBetterTogetherEnabled();
|
|
1516
|
+
const telephonyTaskType = this.getWxAppTelephonyTaskType();
|
|
1517
|
+
if (loginOption === _types.LoginOption.BROWSER) {
|
|
1518
|
+
if (flagEnabled) {
|
|
1519
|
+
(0, _wxAppDiagnosticLogging.logWxAppSessionReadiness)({
|
|
1520
|
+
enableWxBetterTogether: true,
|
|
1521
|
+
loginOption,
|
|
1522
|
+
wxAppHooksApplied: false,
|
|
1523
|
+
usersubPublished: false,
|
|
1524
|
+
mercurySubscribed: false,
|
|
1525
|
+
telephonyTaskType,
|
|
1526
|
+
skipReason: 'unsupported_browser_login'
|
|
1527
|
+
});
|
|
1528
|
+
this.metricsManager.trackEvent(_constants4.METRIC_EVENT_NAMES.WXAPP_SESSION_SKIPPED, {
|
|
1529
|
+
loginOption,
|
|
1530
|
+
enableWxBetterTogether: true,
|
|
1531
|
+
skipReason: 'unsupported_browser_login'
|
|
1532
|
+
}, ['operational', 'behavioral']);
|
|
1533
|
+
}
|
|
1534
|
+
return;
|
|
1535
|
+
}
|
|
1536
|
+
let publishedEnable = false;
|
|
1537
|
+
let wxAppInitStage = 'mercury';
|
|
1538
|
+
try {
|
|
1539
|
+
if (flagEnabled) {
|
|
1540
|
+
this.metricsManager.timeEvent([_constants4.METRIC_EVENT_NAMES.WXAPP_SESSION_INIT_SUCCESS, _constants4.METRIC_EVENT_NAMES.WXAPP_SESSION_INIT_FAILED]);
|
|
1541
|
+
await this.ensureWxAppMercuryAndSubscribe();
|
|
1542
|
+
wxAppInitStage = 'publish';
|
|
1543
|
+
await this.publishAnswerOnWebexCrossClientState(true);
|
|
1544
|
+
publishedEnable = true;
|
|
1545
|
+
this.taskManager.syncWxAppMuteFromCallDetailsForAllTasks();
|
|
1546
|
+
const mercurySubscribed = this.wxAppTelephonyMercurySync.isSubscribed();
|
|
1547
|
+
const usersubPublished = this.webexCrossClientService.isAnswerCallsStateActive();
|
|
1548
|
+
(0, _wxAppDiagnosticLogging.logWxAppSessionReadiness)({
|
|
1549
|
+
enableWxBetterTogether: true,
|
|
1550
|
+
loginOption,
|
|
1551
|
+
wxAppHooksApplied: true,
|
|
1552
|
+
usersubPublished,
|
|
1553
|
+
mercurySubscribed,
|
|
1554
|
+
telephonyTaskType
|
|
1555
|
+
});
|
|
1556
|
+
const sessionInitReady = mercurySubscribed && usersubPublished;
|
|
1557
|
+
if (sessionInitReady) {
|
|
1558
|
+
this.metricsManager.trackEvent(_constants4.METRIC_EVENT_NAMES.WXAPP_SESSION_INIT_SUCCESS, {
|
|
1559
|
+
loginOption,
|
|
1560
|
+
enableWxBetterTogether: true
|
|
1561
|
+
}, ['operational', 'behavioral']);
|
|
1562
|
+
} else {
|
|
1563
|
+
this.metricsManager.trackEvent(_constants4.METRIC_EVENT_NAMES.WXAPP_SESSION_INIT_FAILED, {
|
|
1564
|
+
loginOption,
|
|
1565
|
+
enableWxBetterTogether: true,
|
|
1566
|
+
skipReason: !usersubPublished ? 'usersub_not_published' : 'mercury_not_subscribed'
|
|
1567
|
+
}, ['operational', 'behavioral']);
|
|
1568
|
+
}
|
|
1569
|
+
} else {
|
|
1570
|
+
await this.ensureWxAppDeviceRegistered();
|
|
1571
|
+
await this.publishAnswerOnWebexCrossClientState(false, {
|
|
1572
|
+
force: true
|
|
1573
|
+
});
|
|
1574
|
+
this.webexCrossClientService.teardown();
|
|
1575
|
+
this.wxAppTelephonyMercurySync.unsubscribe();
|
|
1576
|
+
await this.releaseWxAppMercuryResources();
|
|
1577
|
+
(0, _wxAppDiagnosticLogging.logWxAppSessionReadiness)({
|
|
1578
|
+
enableWxBetterTogether: false,
|
|
1579
|
+
loginOption,
|
|
1580
|
+
wxAppHooksApplied: true,
|
|
1581
|
+
usersubPublished: false,
|
|
1582
|
+
mercurySubscribed: false,
|
|
1583
|
+
telephonyTaskType,
|
|
1584
|
+
skipReason: 'flag_disabled'
|
|
1585
|
+
});
|
|
1586
|
+
this.metricsManager.trackEvent(_constants4.METRIC_EVENT_NAMES.WXAPP_SESSION_SKIPPED, {
|
|
1587
|
+
loginOption,
|
|
1588
|
+
enableWxBetterTogether: false,
|
|
1589
|
+
skipReason: 'flag_disabled'
|
|
1590
|
+
}, ['operational', 'behavioral']);
|
|
1591
|
+
}
|
|
1592
|
+
} catch (error) {
|
|
1593
|
+
_loggerProxy.default.error(`Failed to initialize wxApp post-station-login: ${error}`, {
|
|
1594
|
+
module: _constants.CC_FILE,
|
|
1595
|
+
method: _constants.METHODS.STATION_LOGIN
|
|
1596
|
+
});
|
|
1597
|
+
if (flagEnabled) {
|
|
1598
|
+
const sessionInitFailureReason = wxAppInitStage === 'mercury' ? 'mercury_subscribe_failed' : 'publish_failed';
|
|
1599
|
+
this.metricsManager.trackEvent(_constants4.METRIC_EVENT_NAMES.WXAPP_SESSION_INIT_FAILED, {
|
|
1600
|
+
loginOption,
|
|
1601
|
+
enableWxBetterTogether: true,
|
|
1602
|
+
skipReason: sessionInitFailureReason,
|
|
1603
|
+
error: error instanceof Error ? error.toString() : String(error)
|
|
1604
|
+
}, ['operational', 'behavioral']);
|
|
1605
|
+
(0, _wxAppDiagnosticLogging.logWxAppSessionReadiness)({
|
|
1606
|
+
enableWxBetterTogether: true,
|
|
1607
|
+
loginOption,
|
|
1608
|
+
wxAppHooksApplied: false,
|
|
1609
|
+
usersubPublished: publishedEnable && this.webexCrossClientService.isAnswerCallsStateActive(),
|
|
1610
|
+
mercurySubscribed: this.wxAppTelephonyMercurySync.isSubscribed(),
|
|
1611
|
+
telephonyTaskType,
|
|
1612
|
+
skipReason: sessionInitFailureReason
|
|
1613
|
+
});
|
|
1614
|
+
if (publishedEnable) {
|
|
1615
|
+
await this.revertWxAppCrossClientPublish();
|
|
1616
|
+
} else {
|
|
1617
|
+
this.wxAppTelephonyMercurySync.unsubscribe();
|
|
1618
|
+
await this.releaseWxAppMercuryResources();
|
|
1619
|
+
}
|
|
1620
|
+
this.resetEnableWxBetterTogetherConfig();
|
|
1621
|
+
} else {
|
|
1622
|
+
this.scheduleForcedFalsePublishRetry();
|
|
1623
|
+
}
|
|
1624
|
+
}
|
|
1625
|
+
}
|
|
1626
|
+
clearWxAppFalsePublishRetryTimer() {
|
|
1627
|
+
if (this.wxAppFalsePublishRetryTimer) {
|
|
1628
|
+
clearTimeout(this.wxAppFalsePublishRetryTimer);
|
|
1629
|
+
this.wxAppFalsePublishRetryTimer = undefined;
|
|
1630
|
+
}
|
|
1631
|
+
}
|
|
1632
|
+
scheduleForcedFalsePublishRetry(retryAttempt = 0) {
|
|
1633
|
+
this.scheduleFalsePublishRetry(retryAttempt, {
|
|
1634
|
+
requireDisabled: true
|
|
1635
|
+
});
|
|
1636
|
+
}
|
|
1637
|
+
|
|
1638
|
+
/**
|
|
1639
|
+
* Retries compensating false publish after rollback failure, regardless of enabled flag.
|
|
1640
|
+
* @private
|
|
1641
|
+
*/
|
|
1642
|
+
scheduleCompensatingFalsePublishRetry(retryAttempt = 0) {
|
|
1643
|
+
this.scheduleFalsePublishRetry(retryAttempt);
|
|
1644
|
+
}
|
|
1645
|
+
scheduleFalsePublishRetry(retryAttempt = 0, options = {}) {
|
|
1646
|
+
if (retryAttempt >= ContactCenter.WXAPP_FALSE_PUBLISH_MAX_RETRIES) {
|
|
1647
|
+
return;
|
|
1648
|
+
}
|
|
1649
|
+
if (options?.requireDisabled && this.isWxBetterTogetherEnabled()) {
|
|
1650
|
+
return;
|
|
1651
|
+
}
|
|
1652
|
+
this.clearWxAppFalsePublishRetryTimer();
|
|
1653
|
+
this.wxAppFalsePublishRetryTimer = setTimeout(async () => {
|
|
1654
|
+
this.wxAppFalsePublishRetryTimer = undefined;
|
|
1655
|
+
if (options?.requireDisabled && this.isWxBetterTogetherEnabled()) {
|
|
1656
|
+
return;
|
|
1657
|
+
}
|
|
1658
|
+
if (!options?.requireDisabled && this.isWxBetterTogetherEnabled() && this.webexCrossClientService.isAnswerCallsStateActive()) {
|
|
1659
|
+
return;
|
|
1660
|
+
}
|
|
1661
|
+
try {
|
|
1662
|
+
await this.ensureWxAppDeviceRegistered();
|
|
1663
|
+
await this.publishAnswerOnWebexCrossClientState(false, {
|
|
1664
|
+
force: true
|
|
1665
|
+
});
|
|
1666
|
+
this.webexCrossClientService.teardown();
|
|
1667
|
+
this.wxAppTelephonyMercurySync.unsubscribe();
|
|
1668
|
+
await this.releaseWxAppMercuryResources();
|
|
1669
|
+
} catch (retryError) {
|
|
1670
|
+
_loggerProxy.default.error(`Failed to retry forced answer-calls-on-wxcc false publish: ${retryError}`, {
|
|
1671
|
+
module: _constants.CC_FILE,
|
|
1672
|
+
method: _constants.METHODS.SET_MANAGE_WEBEX_CALLING_IN_WXCC
|
|
1673
|
+
});
|
|
1674
|
+
this.scheduleFalsePublishRetry(retryAttempt + 1, options);
|
|
1675
|
+
}
|
|
1676
|
+
}, ContactCenter.WXAPP_FALSE_PUBLISH_RETRY_DELAY_MS);
|
|
1677
|
+
}
|
|
1678
|
+
|
|
1679
|
+
/**
|
|
1680
|
+
* Best-effort rollback when usersub true was published but wxApp setup did not complete.
|
|
1681
|
+
* @private
|
|
1682
|
+
*/
|
|
1683
|
+
async revertWxAppCrossClientPublish() {
|
|
1684
|
+
try {
|
|
1685
|
+
await this.publishAnswerOnWebexCrossClientState(false, {
|
|
1686
|
+
force: true
|
|
1687
|
+
});
|
|
1688
|
+
} catch (error) {
|
|
1689
|
+
_loggerProxy.default.error(`Failed to publish compensating answer-calls-on-wxcc false during wxApp rollback: ${error}`, {
|
|
1690
|
+
module: _constants.CC_FILE,
|
|
1691
|
+
method: _constants.METHODS.SET_MANAGE_WEBEX_CALLING_IN_WXCC
|
|
1692
|
+
});
|
|
1693
|
+
this.scheduleCompensatingFalsePublishRetry();
|
|
1694
|
+
}
|
|
1695
|
+
this.webexCrossClientService.teardown();
|
|
1696
|
+
this.wxAppTelephonyMercurySync.unsubscribe();
|
|
1697
|
+
await this.releaseWxAppMercuryResources();
|
|
1698
|
+
}
|
|
1699
|
+
async ensureWxAppDeviceRegistered() {
|
|
1700
|
+
const device = this.$webex.internal.device;
|
|
1701
|
+
if (device && !device.registered && device.register) {
|
|
1702
|
+
await device.register();
|
|
1703
|
+
this.wxAppDeviceRegisteredByCc = true;
|
|
1704
|
+
_loggerProxy.default.log('WxApp: device registered for cross-client publish', {
|
|
1705
|
+
module: _constants.CC_FILE,
|
|
1706
|
+
method: _constants.METHODS.ENSURE_WXAPP_MERCURY_CONNECTED
|
|
1707
|
+
});
|
|
1708
|
+
}
|
|
1709
|
+
}
|
|
1710
|
+
async ensureWxAppMercuryConnected() {
|
|
1711
|
+
const mercury = this.$webex.internal.mercury;
|
|
1712
|
+
await this.ensureWxAppDeviceRegistered();
|
|
1713
|
+
if (mercury && !mercury.connected) {
|
|
1714
|
+
await mercury.connect();
|
|
1715
|
+
this.wxAppMercuryConnectedByCc = true;
|
|
1716
|
+
_loggerProxy.default.log('WxApp mute sync: mercury connected', {
|
|
1717
|
+
module: _constants.CC_FILE,
|
|
1718
|
+
method: _constants.METHODS.ENSURE_WXAPP_MERCURY_CONNECTED
|
|
1719
|
+
});
|
|
1720
|
+
}
|
|
1721
|
+
}
|
|
1722
|
+
|
|
1723
|
+
/**
|
|
1724
|
+
* Disconnects Mercury and unregisters the device when wxApp mute sync opened them.
|
|
1725
|
+
* @private
|
|
1726
|
+
*/
|
|
1727
|
+
async releaseWxAppMercuryResources() {
|
|
1728
|
+
const mercury = this.$webex.internal.mercury;
|
|
1729
|
+
const device = this.$webex.internal.device;
|
|
1730
|
+
if (this.wxAppMercuryConnectedByCc && mercury?.connected) {
|
|
1731
|
+
try {
|
|
1732
|
+
await mercury.disconnect();
|
|
1733
|
+
this.wxAppMercuryConnectedByCc = false;
|
|
1734
|
+
_loggerProxy.default.log('WxApp mute sync: mercury disconnected', {
|
|
1735
|
+
module: _constants.CC_FILE,
|
|
1736
|
+
method: _constants.METHODS.ENSURE_WXAPP_MERCURY_CONNECTED
|
|
1737
|
+
});
|
|
1738
|
+
} catch (error) {
|
|
1739
|
+
_loggerProxy.default.error(`Failed to disconnect wxApp Mercury: ${error}`, {
|
|
1740
|
+
module: _constants.CC_FILE,
|
|
1741
|
+
method: _constants.METHODS.ENSURE_WXAPP_MERCURY_CONNECTED
|
|
1742
|
+
});
|
|
1743
|
+
}
|
|
1744
|
+
}
|
|
1745
|
+
if (this.wxAppDeviceRegisteredByCc && device?.registered && device.unregister) {
|
|
1746
|
+
try {
|
|
1747
|
+
// @ts-ignore
|
|
1748
|
+
await device.unregister();
|
|
1749
|
+
this.wxAppDeviceRegisteredByCc = false;
|
|
1750
|
+
_loggerProxy.default.log('WxApp mute sync: device unregistered', {
|
|
1751
|
+
module: _constants.CC_FILE,
|
|
1752
|
+
method: _constants.METHODS.ENSURE_WXAPP_MERCURY_CONNECTED
|
|
1753
|
+
});
|
|
1754
|
+
} catch (error) {
|
|
1755
|
+
_loggerProxy.default.error(`Failed to unregister wxApp device: ${error}`, {
|
|
1756
|
+
module: _constants.CC_FILE,
|
|
1757
|
+
method: _constants.METHODS.ENSURE_WXAPP_MERCURY_CONNECTED
|
|
1758
|
+
});
|
|
1759
|
+
}
|
|
1760
|
+
} else if (this.wxAppDeviceRegisteredByCc) {
|
|
1761
|
+
this.wxAppDeviceRegisteredByCc = false;
|
|
1762
|
+
}
|
|
1763
|
+
}
|
|
1764
|
+
|
|
1765
|
+
/**
|
|
1766
|
+
* Clears wxApp runtime state and feature-owned resources. Publish failures are logged;
|
|
1767
|
+
* optional rethrow for deregister when callers need to surface usersub errors.
|
|
1768
|
+
* @private
|
|
1769
|
+
*/
|
|
1770
|
+
async teardownWxAppLocalState(options) {
|
|
1771
|
+
this.clearWxAppFalsePublishRetryTimer();
|
|
1772
|
+
let publishError;
|
|
1773
|
+
try {
|
|
1774
|
+
const shouldForceFalsePublish = this.isWxBetterTogetherEnabled() || this.webexCrossClientService.isAnswerCallsStateActive();
|
|
1775
|
+
await this.publishAnswerOnWebexCrossClientState(false, {
|
|
1776
|
+
force: shouldForceFalsePublish
|
|
1777
|
+
});
|
|
1778
|
+
} catch (error) {
|
|
1779
|
+
publishError = error;
|
|
1780
|
+
_loggerProxy.default.error(`Failed to publish answer-calls-on-wxcc false during wxApp teardown: ${error}`, {
|
|
1781
|
+
module: _constants.CC_FILE,
|
|
1782
|
+
method: _constants.METHODS.SET_MANAGE_WEBEX_CALLING_IN_WXCC
|
|
1783
|
+
});
|
|
1784
|
+
}
|
|
1785
|
+
this.webexCrossClientService.teardown();
|
|
1786
|
+
this.wxAppTelephonyMercurySync.unsubscribe();
|
|
1787
|
+
await this.releaseWxAppMercuryResources();
|
|
1788
|
+
if (options?.clearInitFlag) {
|
|
1789
|
+
this.resetEnableWxBetterTogetherConfig();
|
|
1790
|
+
}
|
|
1791
|
+
if (publishError) {
|
|
1792
|
+
this.scheduleCompensatingFalsePublishRetry();
|
|
1793
|
+
}
|
|
1794
|
+
if (options?.rethrowPublishError && publishError) {
|
|
1795
|
+
throw publishError;
|
|
1796
|
+
}
|
|
1797
|
+
return {
|
|
1798
|
+
publishError: publishError ?? undefined
|
|
1799
|
+
};
|
|
1800
|
+
}
|
|
1801
|
+
async ensureWxAppMercuryAndSubscribe() {
|
|
1802
|
+
if (!this.isWxBetterTogetherEnabled()) {
|
|
1803
|
+
return;
|
|
1804
|
+
}
|
|
1805
|
+
if (this.getCurrentStationLoginOption() === _types.LoginOption.BROWSER) {
|
|
1806
|
+
return;
|
|
1807
|
+
}
|
|
1808
|
+
const agentId = this.agentConfig?.agentId;
|
|
1809
|
+
if (!agentId) {
|
|
1810
|
+
_loggerProxy.default.error('Cannot subscribe wxApp mute sync: agentId unavailable', {
|
|
1811
|
+
module: _constants.CC_FILE,
|
|
1812
|
+
method: _constants.METHODS.SYNC_WXAPP_MUTE_FROM_MERCURY
|
|
1813
|
+
});
|
|
1814
|
+
this.metricsManager.trackEvent(_constants4.METRIC_EVENT_NAMES.WXAPP_MERCURY_SUBSCRIBE_FAILED, {
|
|
1815
|
+
error: 'agentId unavailable'
|
|
1816
|
+
}, ['operational', 'behavioral']);
|
|
1817
|
+
return;
|
|
1818
|
+
}
|
|
1819
|
+
try {
|
|
1820
|
+
await this.ensureWxAppMercuryConnected();
|
|
1821
|
+
this.wxAppTelephonyMercurySync.subscribe(agentId, (callId, muted) => {
|
|
1822
|
+
this.taskManager.applyWxAppMuteStateFromSync(callId, muted);
|
|
1823
|
+
});
|
|
1824
|
+
} catch (error) {
|
|
1825
|
+
_loggerProxy.default.error(`Failed to ensure wxApp Mercury mute sync: ${error}`, {
|
|
1826
|
+
module: _constants.CC_FILE,
|
|
1827
|
+
method: _constants.METHODS.SYNC_WXAPP_MUTE_FROM_MERCURY
|
|
1828
|
+
});
|
|
1829
|
+
this.metricsManager.trackEvent(_constants4.METRIC_EVENT_NAMES.WXAPP_MERCURY_SUBSCRIBE_FAILED, {
|
|
1830
|
+
error: error instanceof Error ? error.toString() : String(error)
|
|
1831
|
+
}, ['operational', 'behavioral']);
|
|
1832
|
+
this.wxAppTelephonyMercurySync.unsubscribe();
|
|
1833
|
+
await this.releaseWxAppMercuryResources();
|
|
1834
|
+
throw error;
|
|
1835
|
+
}
|
|
1836
|
+
}
|
|
1837
|
+
async publishAnswerOnWebexCrossClientState(enable, options) {
|
|
1838
|
+
if (enable && !this.isWxBetterTogetherEnabled()) {
|
|
1839
|
+
return;
|
|
1840
|
+
}
|
|
1841
|
+
if (!enable && !options?.force && !this.webexCrossClientService.isAnswerCallsStateActive()) {
|
|
1842
|
+
return;
|
|
1843
|
+
}
|
|
1844
|
+
const userId = this.$webex.internal.device?.userId;
|
|
1845
|
+
if (!userId) {
|
|
1846
|
+
if (enable && this.isWxBetterTogetherEnabled()) {
|
|
1847
|
+
this.metricsManager.trackEvent(_constants4.METRIC_EVENT_NAMES.WXAPP_USERSUB_PUBLISH_FAILED, {
|
|
1848
|
+
enableWxBetterTogether: true,
|
|
1849
|
+
skipReason: 'user_id_unavailable',
|
|
1850
|
+
error: 'User ID is unavailable for cross-client publish'
|
|
1851
|
+
}, ['operational', 'behavioral']);
|
|
1852
|
+
}
|
|
1853
|
+
return;
|
|
1854
|
+
}
|
|
1855
|
+
await this.webexCrossClientService.setManageWebexCallingInWxcc(enable, {
|
|
1856
|
+
userId,
|
|
1857
|
+
trackPublishMetrics: true
|
|
1858
|
+
});
|
|
1859
|
+
if (enable) {
|
|
1860
|
+
this.clearWxAppFalsePublishRetryTimer();
|
|
1861
|
+
}
|
|
1862
|
+
}
|
|
1863
|
+
|
|
1074
1864
|
/**
|
|
1075
1865
|
* Initializes event listeners for the Contact Center service
|
|
1076
1866
|
* Sets up handlers for connection state changes and other core events
|
|
@@ -1102,13 +1892,13 @@ class ContactCenter extends _webexCore.WebexPlugin {
|
|
|
1102
1892
|
async handleConnectionLost(msg) {
|
|
1103
1893
|
if (msg.isConnectionLost) {
|
|
1104
1894
|
// TODO: Emit an event saying connection is lost
|
|
1105
|
-
_loggerProxy.default.
|
|
1895
|
+
_loggerProxy.default.log('event=handleConnectionLost | Connection lost', {
|
|
1106
1896
|
module: _constants.CC_FILE,
|
|
1107
1897
|
method: _constants.METHODS.HANDLE_CONNECTION_LOST
|
|
1108
1898
|
});
|
|
1109
1899
|
} else if (msg.isSocketReconnected) {
|
|
1110
1900
|
// TODO: Emit an event saying connection is re-estabilished
|
|
1111
|
-
_loggerProxy.default.
|
|
1901
|
+
_loggerProxy.default.log('event=handleConnectionReconnect | Connection reconnected attempting to request silent relogin', {
|
|
1112
1902
|
module: _constants.CC_FILE,
|
|
1113
1903
|
method: _constants.METHODS.HANDLE_CONNECTION_LOST
|
|
1114
1904
|
});
|
|
@@ -1123,12 +1913,13 @@ class ContactCenter extends _webexCore.WebexPlugin {
|
|
|
1123
1913
|
* @private
|
|
1124
1914
|
*/
|
|
1125
1915
|
async silentRelogin() {
|
|
1126
|
-
_loggerProxy.default.
|
|
1916
|
+
_loggerProxy.default.log('Starting silent relogin process', {
|
|
1127
1917
|
module: _constants.CC_FILE,
|
|
1128
1918
|
method: _constants.METHODS.SILENT_RELOGIN
|
|
1129
1919
|
});
|
|
1130
1920
|
try {
|
|
1131
1921
|
const reLoginResponse = await this.services.agent.reload();
|
|
1922
|
+
this.updateWellnessSession(reLoginResponse.data.agentSessionId);
|
|
1132
1923
|
const {
|
|
1133
1924
|
agentId,
|
|
1134
1925
|
lastStateChangeReason,
|
|
@@ -1145,7 +1936,7 @@ class ContactCenter extends _webexCore.WebexPlugin {
|
|
|
1145
1936
|
this.agentConfig.currentTeamId = reLoginResponse.data.teamId;
|
|
1146
1937
|
await this.handleDeviceType(deviceType, dn);
|
|
1147
1938
|
if (lastStateChangeReason === 'agent-wss-disconnect') {
|
|
1148
|
-
_loggerProxy.default.
|
|
1939
|
+
_loggerProxy.default.log('event=requestAutoStateChange | Requesting state change to available on socket reconnect', {
|
|
1149
1940
|
module: _constants.CC_FILE,
|
|
1150
1941
|
method: _constants.METHODS.SILENT_RELOGIN
|
|
1151
1942
|
});
|
|
@@ -1169,8 +1960,7 @@ class ContactCenter extends _webexCore.WebexPlugin {
|
|
|
1169
1960
|
}
|
|
1170
1961
|
this.agentConfig.lastStateAuxCodeId = auxCodeId;
|
|
1171
1962
|
this.agentConfig.isAgentLoggedIn = true;
|
|
1172
|
-
|
|
1173
|
-
this.services.webSocketManager.on('message', this.handleWebsocketMessage);
|
|
1963
|
+
await this.ensureWxAppPostStationLogin();
|
|
1174
1964
|
_loggerProxy.default.log(`Silent relogin process completed successfully with login Option: ${reLoginResponse.data.deviceType} teamId: ${reLoginResponse.data.teamId}`, {
|
|
1175
1965
|
module: _constants.CC_FILE,
|
|
1176
1966
|
method: _constants.METHODS.SILENT_RELOGIN,
|
|
@@ -1205,6 +1995,13 @@ class ContactCenter extends _webexCore.WebexPlugin {
|
|
|
1205
1995
|
this.agentConfig.deviceType = deviceType;
|
|
1206
1996
|
switch (deviceType) {
|
|
1207
1997
|
case _types.LoginOption.BROWSER:
|
|
1998
|
+
if (this.isWebRTCRegistrationDisabled()) {
|
|
1999
|
+
_loggerProxy.default.info('Skipping web calling line registration because disableWebRTCRegistration is enabled', {
|
|
2000
|
+
module: _constants.CC_FILE,
|
|
2001
|
+
method: _constants.METHODS.HANDLE_DEVICE_TYPE
|
|
2002
|
+
});
|
|
2003
|
+
break;
|
|
2004
|
+
}
|
|
1208
2005
|
try {
|
|
1209
2006
|
await this.webCallingService.registerWebCallingLine();
|
|
1210
2007
|
} catch (error) {
|
|
@@ -1444,6 +2241,138 @@ class ContactCenter extends _webexCore.WebexPlugin {
|
|
|
1444
2241
|
}
|
|
1445
2242
|
}
|
|
1446
2243
|
|
|
2244
|
+
/**
|
|
2245
|
+
* Skips a campaign preview contact, requesting the next contact from the campaign.
|
|
2246
|
+
*
|
|
2247
|
+
* When a campaign manager reserves a contact for an agent, the agent receives an
|
|
2248
|
+
* `AgentOfferCampaignReservation` event. Instead of accepting, the agent can skip the
|
|
2249
|
+
* preview contact to move to the next contact in the campaign.
|
|
2250
|
+
*
|
|
2251
|
+
* @param {PreviewContactPayload} payload - The preview contact payload containing interactionId and campaignId (campaign name, not UUID).
|
|
2252
|
+
* @returns {Promise<TaskResponse>} Promise resolving with agent contact on success.
|
|
2253
|
+
* @throws {Error} If the operation fails (network error, etc.)
|
|
2254
|
+
*
|
|
2255
|
+
* @example
|
|
2256
|
+
* ```typescript
|
|
2257
|
+
* webex.cc.on('task:campaignPreviewReservation', async (task) => {
|
|
2258
|
+
* const { interactionId } = task.data;
|
|
2259
|
+
* const campaignId = task.data.interaction.callProcessingDetails.campaignId;
|
|
2260
|
+
*
|
|
2261
|
+
* const result = await webex.cc.skipPreviewContact({ interactionId, campaignId });
|
|
2262
|
+
* });
|
|
2263
|
+
* ```
|
|
2264
|
+
*/
|
|
2265
|
+
async skipPreviewContact(payload) {
|
|
2266
|
+
const task = this.taskManager.getTask(payload.interactionId);
|
|
2267
|
+
if (task?.data?.interaction?.callProcessingDetails?.campaignPreviewSkipDisabled === 'true') {
|
|
2268
|
+
_loggerProxy.default.warn('Skip action is disabled for this campaign preview contact', {
|
|
2269
|
+
module: _constants.CC_FILE,
|
|
2270
|
+
method: _constants.METHODS.SKIP_PREVIEW_CONTACT,
|
|
2271
|
+
interactionId: payload.interactionId
|
|
2272
|
+
});
|
|
2273
|
+
throw new Error('Skip action is disabled for this campaign preview contact');
|
|
2274
|
+
}
|
|
2275
|
+
_loggerProxy.default.info('Skipping campaign preview contact', {
|
|
2276
|
+
module: _constants.CC_FILE,
|
|
2277
|
+
method: _constants.METHODS.SKIP_PREVIEW_CONTACT
|
|
2278
|
+
});
|
|
2279
|
+
try {
|
|
2280
|
+
this.metricsManager.timeEvent([_constants4.METRIC_EVENT_NAMES.CAMPAIGN_PREVIEW_SKIP_SUCCESS, _constants4.METRIC_EVENT_NAMES.CAMPAIGN_PREVIEW_SKIP_FAILED]);
|
|
2281
|
+
const result = await this.services.dialer.skipPreviewContact({
|
|
2282
|
+
data: payload
|
|
2283
|
+
});
|
|
2284
|
+
this.metricsManager.trackEvent(_constants4.METRIC_EVENT_NAMES.CAMPAIGN_PREVIEW_SKIP_SUCCESS, {
|
|
2285
|
+
..._MetricsManager.default.getCommonTrackingFieldForAQMResponse(result),
|
|
2286
|
+
interactionId: payload.interactionId,
|
|
2287
|
+
campaignId: payload.campaignId
|
|
2288
|
+
}, ['behavioral', 'business', 'operational']);
|
|
2289
|
+
_loggerProxy.default.log('Campaign preview contact skipped successfully', {
|
|
2290
|
+
module: _constants.CC_FILE,
|
|
2291
|
+
method: _constants.METHODS.SKIP_PREVIEW_CONTACT,
|
|
2292
|
+
trackingId: result.trackingId,
|
|
2293
|
+
interactionId: payload.interactionId
|
|
2294
|
+
});
|
|
2295
|
+
return result;
|
|
2296
|
+
} catch (error) {
|
|
2297
|
+
const failure = error.details;
|
|
2298
|
+
this.metricsManager.trackEvent(_constants4.METRIC_EVENT_NAMES.CAMPAIGN_PREVIEW_SKIP_FAILED, {
|
|
2299
|
+
..._MetricsManager.default.getCommonTrackingFieldForAQMResponseFailed(failure),
|
|
2300
|
+
interactionId: payload.interactionId,
|
|
2301
|
+
campaignId: payload.campaignId
|
|
2302
|
+
}, ['behavioral', 'business', 'operational']);
|
|
2303
|
+
const {
|
|
2304
|
+
error: detailedError
|
|
2305
|
+
} = (0, _Utils.getErrorDetails)(error, _constants.METHODS.SKIP_PREVIEW_CONTACT, _constants.CC_FILE);
|
|
2306
|
+
throw detailedError;
|
|
2307
|
+
}
|
|
2308
|
+
}
|
|
2309
|
+
|
|
2310
|
+
/**
|
|
2311
|
+
* Removes a campaign preview contact from the campaign list entirely.
|
|
2312
|
+
*
|
|
2313
|
+
* When a campaign manager reserves a contact for an agent, the agent receives an
|
|
2314
|
+
* `AgentOfferCampaignReservation` event. Instead of accepting or skipping, the agent can
|
|
2315
|
+
* remove the preview contact to permanently take it out of the campaign contact list.
|
|
2316
|
+
*
|
|
2317
|
+
* @param {PreviewContactPayload} payload - The preview contact payload containing interactionId and campaignId (campaign name, not UUID).
|
|
2318
|
+
* @returns {Promise<TaskResponse>} Promise resolving with agent contact on success.
|
|
2319
|
+
* @throws {Error} If the operation fails (network error, etc.)
|
|
2320
|
+
*
|
|
2321
|
+
* @example
|
|
2322
|
+
* ```typescript
|
|
2323
|
+
* webex.cc.on('task:campaignPreviewReservation', async (task) => {
|
|
2324
|
+
* const { interactionId } = task.data;
|
|
2325
|
+
* const campaignId = task.data.interaction.callProcessingDetails.campaignId;
|
|
2326
|
+
*
|
|
2327
|
+
* const result = await webex.cc.removePreviewContact({ interactionId, campaignId });
|
|
2328
|
+
* });
|
|
2329
|
+
* ```
|
|
2330
|
+
*/
|
|
2331
|
+
async removePreviewContact(payload) {
|
|
2332
|
+
const task = this.taskManager.getTask(payload.interactionId);
|
|
2333
|
+
if (task?.data?.interaction?.callProcessingDetails?.campaignPreviewRemoveDisabled === 'true') {
|
|
2334
|
+
_loggerProxy.default.warn('Remove action is disabled for this campaign preview contact', {
|
|
2335
|
+
module: _constants.CC_FILE,
|
|
2336
|
+
method: _constants.METHODS.REMOVE_PREVIEW_CONTACT,
|
|
2337
|
+
interactionId: payload.interactionId
|
|
2338
|
+
});
|
|
2339
|
+
throw new Error('Remove action is disabled for this campaign preview contact');
|
|
2340
|
+
}
|
|
2341
|
+
_loggerProxy.default.info('Removing campaign preview contact', {
|
|
2342
|
+
module: _constants.CC_FILE,
|
|
2343
|
+
method: _constants.METHODS.REMOVE_PREVIEW_CONTACT
|
|
2344
|
+
});
|
|
2345
|
+
try {
|
|
2346
|
+
this.metricsManager.timeEvent([_constants4.METRIC_EVENT_NAMES.CAMPAIGN_PREVIEW_REMOVE_SUCCESS, _constants4.METRIC_EVENT_NAMES.CAMPAIGN_PREVIEW_REMOVE_FAILED]);
|
|
2347
|
+
const result = await this.services.dialer.removePreviewContact({
|
|
2348
|
+
data: payload
|
|
2349
|
+
});
|
|
2350
|
+
this.metricsManager.trackEvent(_constants4.METRIC_EVENT_NAMES.CAMPAIGN_PREVIEW_REMOVE_SUCCESS, {
|
|
2351
|
+
..._MetricsManager.default.getCommonTrackingFieldForAQMResponse(result),
|
|
2352
|
+
interactionId: payload.interactionId,
|
|
2353
|
+
campaignId: payload.campaignId
|
|
2354
|
+
}, ['behavioral', 'business', 'operational']);
|
|
2355
|
+
_loggerProxy.default.log('Campaign preview contact removed successfully', {
|
|
2356
|
+
module: _constants.CC_FILE,
|
|
2357
|
+
method: _constants.METHODS.REMOVE_PREVIEW_CONTACT,
|
|
2358
|
+
trackingId: result.trackingId,
|
|
2359
|
+
interactionId: payload.interactionId
|
|
2360
|
+
});
|
|
2361
|
+
return result;
|
|
2362
|
+
} catch (error) {
|
|
2363
|
+
const failure = error.details;
|
|
2364
|
+
this.metricsManager.trackEvent(_constants4.METRIC_EVENT_NAMES.CAMPAIGN_PREVIEW_REMOVE_FAILED, {
|
|
2365
|
+
..._MetricsManager.default.getCommonTrackingFieldForAQMResponseFailed(failure),
|
|
2366
|
+
interactionId: payload.interactionId,
|
|
2367
|
+
campaignId: payload.campaignId
|
|
2368
|
+
}, ['behavioral', 'business', 'operational']);
|
|
2369
|
+
const {
|
|
2370
|
+
error: detailedError
|
|
2371
|
+
} = (0, _Utils.getErrorDetails)(error, _constants.METHODS.REMOVE_PREVIEW_CONTACT, _constants.CC_FILE);
|
|
2372
|
+
throw detailedError;
|
|
2373
|
+
}
|
|
2374
|
+
}
|
|
2375
|
+
|
|
1447
2376
|
/**
|
|
1448
2377
|
* Fetches outdial ANI (Automatic Number Identification) entries for an outdial ANI ID.
|
|
1449
2378
|
*
|
|
@@ -1648,8 +2577,8 @@ class ContactCenter extends _webexCore.WebexPlugin {
|
|
|
1648
2577
|
}
|
|
1649
2578
|
|
|
1650
2579
|
/**
|
|
1651
|
-
* Returns paginated entry points
|
|
1652
|
-
*
|
|
2580
|
+
* Returns paginated entry points using the EntryPoint service defaults.
|
|
2581
|
+
* Existing request parameters can override those defaults.
|
|
1653
2582
|
* @public
|
|
1654
2583
|
*/
|
|
1655
2584
|
async getEntryPoints(params = {}) {
|
|
@@ -1657,8 +2586,8 @@ class ContactCenter extends _webexCore.WebexPlugin {
|
|
|
1657
2586
|
}
|
|
1658
2587
|
|
|
1659
2588
|
/**
|
|
1660
|
-
* Returns paginated contact service queues
|
|
1661
|
-
*
|
|
2589
|
+
* Returns paginated contact service queues using the Queue service defaults.
|
|
2590
|
+
* Existing request parameters can override those defaults.
|
|
1662
2591
|
* @public
|
|
1663
2592
|
*/
|
|
1664
2593
|
async getQueues(params = {}) {
|