@webex/contact-center 3.12.0-next.12 → 3.12.0-next.121
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 +51 -0
- package/ai-docs/GETTING_STARTED.md +168 -0
- package/ai-docs/GLOSSARY.md +43 -0
- package/ai-docs/README.md +138 -0
- package/ai-docs/REVIEW_CHECKLIST.md +41 -0
- package/ai-docs/RULES.md +444 -0
- package/ai-docs/SECURITY.md +52 -0
- package/ai-docs/SERVICE_STATE.md +48 -0
- package/ai-docs/SPEC_INDEX.md +65 -0
- package/ai-docs/adr/0001-spec-source-policy.md +55 -0
- package/ai-docs/adr/README.md +8 -0
- package/ai-docs/adr/_adr-template.md +31 -0
- package/ai-docs/contact-center-spec.md +359 -0
- package/ai-docs/features/consult-transfer-list-policy/spec/feature-spec.md +362 -0
- package/ai-docs/features/generated-spec-conformance-fidelity-remediation/spec/feature-spec.md +117 -0
- package/ai-docs/features/residual-warning-coverage-completion/spec/feature-spec.md +203 -0
- package/ai-docs/features/validator-code-fidelity-drift-fix/spec/feature-spec.md +315 -0
- package/ai-docs/patterns/event-driven-patterns.md +485 -0
- package/ai-docs/patterns/testing-patterns.md +480 -0
- package/ai-docs/patterns/typescript-patterns.md +365 -0
- package/ai-docs/templates/README.md +102 -0
- package/ai-docs/templates/documentation/create-agents-md.md +240 -0
- package/ai-docs/templates/documentation/create-architecture-md.md +295 -0
- package/ai-docs/templates/existing-service/bug-fix.md +254 -0
- package/ai-docs/templates/existing-service/feature-enhancement.md +450 -0
- package/ai-docs/templates/new-method/00-master.md +80 -0
- package/ai-docs/templates/new-method/01-requirements.md +232 -0
- package/ai-docs/templates/new-method/02-implementation.md +295 -0
- package/ai-docs/templates/new-method/03-tests.md +201 -0
- package/ai-docs/templates/new-method/04-validation.md +141 -0
- package/ai-docs/templates/new-service/00-master.md +109 -0
- package/ai-docs/templates/new-service/01-pre-questions.md +159 -0
- package/ai-docs/templates/new-service/02-code-generation.md +346 -0
- package/ai-docs/templates/new-service/03-integration.md +178 -0
- package/ai-docs/templates/new-service/04-test-generation.md +205 -0
- package/ai-docs/templates/new-service/05-validation.md +145 -0
- package/dist/cc.js +808 -40
- package/dist/cc.js.map +1 -1
- package/dist/config.js +13 -0
- package/dist/config.js.map +1 -1
- package/dist/constants.js +27 -3
- package/dist/constants.js.map +1 -1
- package/dist/index.js +20 -5
- 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 +43 -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 +153 -8
- 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 +6 -3
- package/dist/services/config/Util.js.map +1 -1
- package/dist/services/config/constants.js +33 -8
- package/dist/services/config/constants.js.map +1 -1
- package/dist/services/config/types.js +53 -9
- package/dist/services/config/types.js.map +1 -1
- package/dist/services/core/Err.js.map +1 -1
- package/dist/services/core/Utils.js +107 -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 +1053 -520
- 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 +954 -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 +1447 -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 +172 -5
- package/dist/types/config.d.ts +13 -0
- package/dist/types/constants.d.ts +25 -1
- package/dist/types/index.d.ts +24 -7
- package/dist/types/metrics/MetricsManager.d.ts +6 -0
- package/dist/types/metrics/constants.d.ts +38 -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 +22 -4
- 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 +29 -5
- package/dist/types/services/config/types.d.ts +184 -10
- package/dist/types/services/core/Err.d.ts +6 -0
- package/dist/types/services/core/Utils.d.ts +33 -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 +1356 -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 +149 -8
- package/dist/types/utils/PageCache.d.ts +20 -3
- package/dist/types/webex.d.ts +1 -0
- package/dist/types.js +125 -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 +14 -2
- package/dist/webex.js.map +1 -1
- package/package.json +16 -12
- package/src/cc.ts +986 -42
- package/src/config.ts +13 -0
- package/src/constants.ts +25 -1
- package/src/index.ts +25 -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 +922 -0
- package/src/metrics/behavioral-events.ts +212 -0
- package/src/metrics/constants.ts +47 -4
- package/src/services/AddressBook.ts +17 -6
- package/src/services/AnswerCallOnWebexService.ts +239 -0
- package/src/services/ApiAiAssistant.ts +203 -8
- 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 +497 -0
- package/src/services/config/Util.ts +6 -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 +675 -0
- package/src/services/config/constants.ts +35 -7
- package/src/services/config/types.ts +186 -11
- package/src/services/core/Err.ts +3 -0
- package/src/services/core/Utils.ts +123 -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 +1239 -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 +1470 -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 +1293 -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 +1145 -0
- package/src/services/task/state-machine/ai-docs/task-state-machine-spec.md +2207 -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 +1809 -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 +199 -11
- package/src/utils/AGENTS.md +289 -0
- package/src/utils/PageCache.ts +38 -5
- package/src/utils/ai-docs/utils-spec.md +391 -0
- package/src/webex.js +2 -0
- package/test/unit/spec/cc.ts +1947 -124
- 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 +178 -20
- 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 +85 -0
- package/test/unit/spec/services/config/index.ts +30 -30
- 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 +677 -0
- package/test/unit/spec/services/task/TaskFactory.ts +99 -0
- package/test/unit/spec/services/task/TaskManager.ts +1972 -1549
- 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 +3459 -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 +1903 -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/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
|
|
@@ -274,6 +302,36 @@ class ContactCenter extends _webexCore.WebexPlugin {
|
|
|
274
302
|
* ```
|
|
275
303
|
*/
|
|
276
304
|
|
|
305
|
+
/**
|
|
306
|
+
* API instance for managing Webex Contact Center user preferences
|
|
307
|
+
* Provides functionality to get, create, update, and delete user preferences
|
|
308
|
+
* @type {UserPreference}
|
|
309
|
+
* @public
|
|
310
|
+
* @example
|
|
311
|
+
* ```typescript
|
|
312
|
+
* const cc = webex.cc;
|
|
313
|
+
* await cc.register();
|
|
314
|
+
* await cc.stationLogin({ teamId: 'team123', loginOption: 'BROWSER' });
|
|
315
|
+
*
|
|
316
|
+
* // Get user preferences for current user
|
|
317
|
+
* const preferences = await cc.userPreference.getUserPreference();
|
|
318
|
+
*
|
|
319
|
+
* // Create new user preferences
|
|
320
|
+
* const newPrefs = await cc.userPreference.createUserPreference({
|
|
321
|
+
* userId: 'user123',
|
|
322
|
+
* preferences: { e911Reminder: true }
|
|
323
|
+
* });
|
|
324
|
+
*
|
|
325
|
+
* // Update user preferences
|
|
326
|
+
* const updatedPrefs = await cc.userPreference.updateUserPreference('user123', {
|
|
327
|
+
* preferences: { e911Reminder: false }
|
|
328
|
+
* });
|
|
329
|
+
*
|
|
330
|
+
* // Delete user preferences
|
|
331
|
+
* await cc.userPreference.deleteUserPreference('user123');
|
|
332
|
+
* ```
|
|
333
|
+
*/
|
|
334
|
+
|
|
277
335
|
/**
|
|
278
336
|
* API instance for AI Assistant operations such as transcript controls.
|
|
279
337
|
* @type {ApiAIAssistant}
|
|
@@ -301,6 +359,7 @@ class ContactCenter extends _webexCore.WebexPlugin {
|
|
|
301
359
|
this.$webex.once(_constants.READY, () => {
|
|
302
360
|
// @ts-ignore
|
|
303
361
|
this.$config = this.config;
|
|
362
|
+
this.validatePluginConfig();
|
|
304
363
|
|
|
305
364
|
/**
|
|
306
365
|
* This is used for handling the async requests by sending webex.request and wait for corresponding websocket event.
|
|
@@ -312,13 +371,16 @@ class ContactCenter extends _webexCore.WebexPlugin {
|
|
|
312
371
|
webex: this.$webex,
|
|
313
372
|
connectionConfig: this.getConnectionConfig()
|
|
314
373
|
});
|
|
315
|
-
this.services.webSocketManager.on('message', this.handleWebsocketMessage);
|
|
316
374
|
this.webCallingService = new _WebCallingService.default(this.$webex);
|
|
375
|
+
this.answerCallOnWebexService = new _AnswerCallOnWebexService.default(this.$webex);
|
|
376
|
+
this.webexCrossClientService = new _WebexCrossClientService.default(this.$webex);
|
|
377
|
+
this.wxAppTelephonyMercurySync = new _WxAppTelephonyMercurySync.default(this.$webex);
|
|
317
378
|
this.apiAIAssistant = new _ApiAiAssistant.ApiAIAssistant(this.$webex);
|
|
318
379
|
this.metricsManager = _MetricsManager.default.getInstance({
|
|
319
380
|
webex: this.$webex
|
|
320
381
|
});
|
|
321
|
-
this.taskManager = _TaskManager.default.getTaskManager(this.apiAIAssistant, this.services.contact, this.webCallingService, this.services.webSocketManager);
|
|
382
|
+
this.taskManager = _TaskManager.default.getTaskManager(this.apiAIAssistant, this.services.contact, this.webCallingService, this.services.webSocketManager, this.services.rtdWebSocketManager);
|
|
383
|
+
this.taskManager.setAnswerCallOnWebexService(this.answerCallOnWebexService);
|
|
322
384
|
this.incomingTaskListener();
|
|
323
385
|
|
|
324
386
|
// Initialize API instances
|
|
@@ -326,6 +388,7 @@ class ContactCenter extends _webexCore.WebexPlugin {
|
|
|
326
388
|
this.entryPoint = new _EntryPoint.EntryPoint(this.$webex);
|
|
327
389
|
this.addressBook = new _AddressBook.AddressBook(this.$webex, () => this.agentConfig?.addressBookId);
|
|
328
390
|
this.queue = new _Queue.Queue(this.$webex);
|
|
391
|
+
this.userPreference = new _UserPreference.UserPreference(this.$webex, () => this.agentConfig?.agentId);
|
|
329
392
|
_loggerProxy.default.initialize(this.$webex.logger);
|
|
330
393
|
});
|
|
331
394
|
}
|
|
@@ -350,6 +413,16 @@ class ContactCenter extends _webexCore.WebexPlugin {
|
|
|
350
413
|
this.trigger(_types4.TASK_EVENTS.TASK_HYDRATE, task);
|
|
351
414
|
};
|
|
352
415
|
|
|
416
|
+
/**
|
|
417
|
+
* Handles multi-login hydrate events for SDK instances without Mobius registration
|
|
418
|
+
* @private
|
|
419
|
+
* @param {ITask} task The task object associated with the multi-login hydrate
|
|
420
|
+
*/
|
|
421
|
+
handleTaskMultiLoginHydrate = task => {
|
|
422
|
+
// @ts-ignore
|
|
423
|
+
this.trigger(_types4.TASK_EVENTS.TASK_MULTI_LOGIN_HYDRATE, task);
|
|
424
|
+
};
|
|
425
|
+
|
|
353
426
|
/**
|
|
354
427
|
* Handles task merged events when tasks are combined eg: EPDN merge/transfer
|
|
355
428
|
* @private
|
|
@@ -369,8 +442,8 @@ class ContactCenter extends _webexCore.WebexPlugin {
|
|
|
369
442
|
// @ts-ignore
|
|
370
443
|
this.trigger(_types4.TASK_EVENTS.TASK_CAMPAIGN_PREVIEW_RESERVATION, task);
|
|
371
444
|
};
|
|
372
|
-
handleRTDWebsocketMessage =
|
|
373
|
-
this.taskManager.handleRealtimeWebsocketEvent(
|
|
445
|
+
handleRTDWebsocketMessage = event => {
|
|
446
|
+
this.taskManager.handleRealtimeWebsocketEvent(event);
|
|
374
447
|
};
|
|
375
448
|
|
|
376
449
|
/**
|
|
@@ -381,6 +454,7 @@ class ContactCenter extends _webexCore.WebexPlugin {
|
|
|
381
454
|
incomingTaskListener() {
|
|
382
455
|
this.taskManager.on(_types4.TASK_EVENTS.TASK_INCOMING, this.handleIncomingTask);
|
|
383
456
|
this.taskManager.on(_types4.TASK_EVENTS.TASK_HYDRATE, this.handleTaskHydrate);
|
|
457
|
+
this.taskManager.on(_types4.TASK_EVENTS.TASK_MULTI_LOGIN_HYDRATE, this.handleTaskMultiLoginHydrate);
|
|
384
458
|
this.taskManager.on(_types4.TASK_EVENTS.TASK_MERGED, this.handleTaskMerged);
|
|
385
459
|
this.taskManager.on(_types4.TASK_EVENTS.TASK_CAMPAIGN_PREVIEW_RESERVATION, this.handleCampaignPreviewReservation);
|
|
386
460
|
}
|
|
@@ -422,13 +496,14 @@ class ContactCenter extends _webexCore.WebexPlugin {
|
|
|
422
496
|
* ```
|
|
423
497
|
*/
|
|
424
498
|
async register() {
|
|
425
|
-
_loggerProxy.default.
|
|
499
|
+
_loggerProxy.default.log('Starting CC SDK registration', {
|
|
426
500
|
module: _constants.CC_FILE,
|
|
427
501
|
method: _constants.METHODS.REGISTER
|
|
428
502
|
});
|
|
429
503
|
try {
|
|
430
504
|
this.metricsManager.timeEvent([_constants4.METRIC_EVENT_NAMES.WEBSOCKET_REGISTER_SUCCESS, _constants4.METRIC_EVENT_NAMES.WEBSOCKET_REGISTER_FAILED]);
|
|
431
505
|
this.setupEventListeners();
|
|
506
|
+
this.services.webSocketManager.on('message', this.handleWebsocketMessage);
|
|
432
507
|
const resp = await this.connectWebsocket();
|
|
433
508
|
// Ensure 'dn' is always populated from 'defaultDn'
|
|
434
509
|
resp.dn = resp.defaultDn;
|
|
@@ -491,11 +566,17 @@ class ContactCenter extends _webexCore.WebexPlugin {
|
|
|
491
566
|
this.metricsManager.timeEvent([_constants4.METRIC_EVENT_NAMES.WEBSOCKET_DEREGISTER_SUCCESS, _constants4.METRIC_EVENT_NAMES.WEBSOCKET_DEREGISTER_FAIL]);
|
|
492
567
|
this.taskManager.off(_types4.TASK_EVENTS.TASK_INCOMING, this.handleIncomingTask);
|
|
493
568
|
this.taskManager.off(_types4.TASK_EVENTS.TASK_HYDRATE, this.handleTaskHydrate);
|
|
569
|
+
this.taskManager.off(_types4.TASK_EVENTS.TASK_MULTI_LOGIN_HYDRATE, this.handleTaskMultiLoginHydrate);
|
|
494
570
|
this.taskManager.off(_types4.TASK_EVENTS.TASK_CAMPAIGN_PREVIEW_RESERVATION, this.handleCampaignPreviewReservation);
|
|
495
571
|
this.taskManager.unregisterIncomingCallEvent();
|
|
496
572
|
this.services.webSocketManager.off('message', this.handleWebsocketMessage);
|
|
497
573
|
this.services.rtdWebSocketManager.off('message', this.handleRTDWebsocketMessage);
|
|
498
574
|
this.services.connectionService.off('connectionLost', this.handleConnectionLost);
|
|
575
|
+
const {
|
|
576
|
+
publishError: wxAppPublishError
|
|
577
|
+
} = await this.teardownWxAppLocalState({
|
|
578
|
+
clearInitFlag: true
|
|
579
|
+
});
|
|
499
580
|
if (this.agentConfig.webRtcEnabled && this.agentConfig.loginVoiceOptions.includes(_types.LoginOption.BROWSER)) {
|
|
500
581
|
if (this.$webex.internal.mercury.connected) {
|
|
501
582
|
this.$webex.internal.mercury.off('online');
|
|
@@ -512,12 +593,18 @@ class ContactCenter extends _webexCore.WebexPlugin {
|
|
|
512
593
|
if (!this.services.webSocketManager.isSocketClosed) {
|
|
513
594
|
this.services.webSocketManager.close(false, 'Unregistering the SDK');
|
|
514
595
|
}
|
|
596
|
+
if (this.services.rtdWebSocketManager && !this.services.rtdWebSocketManager.isSocketClosed) {
|
|
597
|
+
this.services.rtdWebSocketManager.close(false, 'Unregistering the SDK');
|
|
598
|
+
}
|
|
515
599
|
if (this.services.rtdWebSocketManager && !this.services.rtdWebSocketManager.isSocketClosed) {
|
|
516
600
|
this.services.rtdWebSocketManager.close(false, 'Unregistering the RTD websocket');
|
|
517
601
|
}
|
|
518
602
|
|
|
519
603
|
// Clear any cached agent configuration
|
|
520
604
|
this.agentConfig = null;
|
|
605
|
+
if (wxAppPublishError) {
|
|
606
|
+
throw wxAppPublishError;
|
|
607
|
+
}
|
|
521
608
|
_loggerProxy.default.log('Deregistered successfully', {
|
|
522
609
|
module: _constants.CC_FILE,
|
|
523
610
|
method: _constants.METHODS.DEREGISTER
|
|
@@ -571,6 +658,12 @@ class ContactCenter extends _webexCore.WebexPlugin {
|
|
|
571
658
|
* ```
|
|
572
659
|
*/
|
|
573
660
|
async getBuddyAgents(data) {
|
|
661
|
+
const {
|
|
662
|
+
action,
|
|
663
|
+
state,
|
|
664
|
+
mediaType = 'telephony'
|
|
665
|
+
} = data;
|
|
666
|
+
const buddyAgentState = state ?? (action === 'Transfer' ? _constants2.AGENT_STATE_AVAILABLE : undefined);
|
|
574
667
|
_loggerProxy.default.info('Fetching buddy agents', {
|
|
575
668
|
module: _constants.CC_FILE,
|
|
576
669
|
method: _constants.METHODS.GET_BUDDY_AGENTS
|
|
@@ -580,13 +673,16 @@ class ContactCenter extends _webexCore.WebexPlugin {
|
|
|
580
673
|
const resp = await this.services.agent.buddyAgents({
|
|
581
674
|
data: {
|
|
582
675
|
agentProfileId: this.agentConfig.agentProfileID,
|
|
583
|
-
|
|
676
|
+
mediaType,
|
|
677
|
+
...(buddyAgentState ? {
|
|
678
|
+
state: buddyAgentState
|
|
679
|
+
} : {})
|
|
584
680
|
}
|
|
585
681
|
});
|
|
586
682
|
this.metricsManager.trackEvent(_constants4.METRIC_EVENT_NAMES.FETCH_BUDDY_AGENTS_SUCCESS, {
|
|
587
683
|
..._MetricsManager.default.getCommonTrackingFieldForAQMResponse(resp),
|
|
588
|
-
mediaType
|
|
589
|
-
buddyAgentState
|
|
684
|
+
mediaType,
|
|
685
|
+
buddyAgentState,
|
|
590
686
|
buddyAgentCount: resp.data.agentList.length
|
|
591
687
|
}, ['operational']);
|
|
592
688
|
_loggerProxy.default.log(`Successfully retrieved ${resp.data.agentList.length} buddy agents`, {
|
|
@@ -599,8 +695,8 @@ class ContactCenter extends _webexCore.WebexPlugin {
|
|
|
599
695
|
const failureResp = error.details;
|
|
600
696
|
this.metricsManager.trackEvent(_constants4.METRIC_EVENT_NAMES.FETCH_BUDDY_AGENTS_FAILED, {
|
|
601
697
|
..._MetricsManager.default.getCommonTrackingFieldForAQMResponseFailed(failureResp),
|
|
602
|
-
mediaType
|
|
603
|
-
buddyAgentState
|
|
698
|
+
mediaType,
|
|
699
|
+
buddyAgentState
|
|
604
700
|
}, ['operational']);
|
|
605
701
|
const {
|
|
606
702
|
error: detailedError
|
|
@@ -616,7 +712,7 @@ class ContactCenter extends _webexCore.WebexPlugin {
|
|
|
616
712
|
* @private
|
|
617
713
|
*/
|
|
618
714
|
async connectWebsocket() {
|
|
619
|
-
_loggerProxy.default.
|
|
715
|
+
_loggerProxy.default.log('Connecting to websocket', {
|
|
620
716
|
module: _constants.CC_FILE,
|
|
621
717
|
method: _constants.METHODS.CONNECT_WEBSOCKET
|
|
622
718
|
});
|
|
@@ -632,18 +728,37 @@ class ContactCenter extends _webexCore.WebexPlugin {
|
|
|
632
728
|
module: _constants.CC_FILE,
|
|
633
729
|
method: _constants.METHODS.CONNECT_WEBSOCKET
|
|
634
730
|
});
|
|
635
|
-
|
|
731
|
+
const configFlags = {
|
|
732
|
+
isEndTaskEnabled: this.agentConfig.isEndTaskEnabled,
|
|
733
|
+
isEndConsultEnabled: this.agentConfig.isEndConsultEnabled,
|
|
734
|
+
webRtcEnabled: this.agentConfig.webRtcEnabled,
|
|
735
|
+
autoWrapup: this.agentConfig.wrapUpData?.wrapUpProps?.autoWrapup ?? false,
|
|
736
|
+
aiFeature: this.agentConfig.aiFeature,
|
|
737
|
+
consultTransfer: {
|
|
738
|
+
allowConsultToQueue: this.agentConfig.allowConsultToQueue,
|
|
739
|
+
accessQueue: this.agentConfig.accessQueue,
|
|
740
|
+
accessEntryPoint: this.agentConfig.accessEntryPoint,
|
|
741
|
+
accessBuddyTeam: this.agentConfig.accessBuddyTeam
|
|
742
|
+
},
|
|
743
|
+
enableWxBetterTogether: this.isWxBetterTogetherEnabled()
|
|
744
|
+
};
|
|
745
|
+
this.taskManager.setConfigFlags(configFlags);
|
|
636
746
|
// TODO: Make profile a singleton to make it available throughout app/sdk so we dont need to inject info everywhere
|
|
637
747
|
this.taskManager.setWrapupData(this.agentConfig.wrapUpData);
|
|
638
748
|
this.taskManager.setAgentId(this.agentConfig.agentId);
|
|
639
749
|
this.taskManager.setWebRtcEnabled(this.agentConfig.webRtcEnabled);
|
|
640
750
|
this.apiAIAssistant.setAIFeatureFlags(this.agentConfig.aiFeature);
|
|
641
|
-
|
|
751
|
+
|
|
752
|
+
/**
|
|
753
|
+
* RTD websocket currently supports realtime transcripts and suggested responses.
|
|
754
|
+
* Extend this condition when additional AI RTD features are introduced.
|
|
755
|
+
*/
|
|
756
|
+
if (this.agentConfig.aiFeature?.realtimeTranscripts?.enable || this.agentConfig.aiFeature?.suggestedResponses?.enable) {
|
|
642
757
|
_loggerProxy.default.info('Connecting to RTD websocket', {
|
|
643
758
|
module: _constants.CC_FILE,
|
|
644
759
|
method: _constants.METHODS.CONNECT_WEBSOCKET
|
|
645
760
|
});
|
|
646
|
-
|
|
761
|
+
this.services.rtdWebSocketManager.initWebSocket({
|
|
647
762
|
body: this.getConnectionConfig(),
|
|
648
763
|
resource: _constants3.RTD_SUBSCRIBE_API
|
|
649
764
|
}).then(() => {
|
|
@@ -653,13 +768,13 @@ class ContactCenter extends _webexCore.WebexPlugin {
|
|
|
653
768
|
});
|
|
654
769
|
this.services.rtdWebSocketManager.on('message', this.handleRTDWebsocketMessage);
|
|
655
770
|
}).catch(error => {
|
|
656
|
-
_loggerProxy.default.error(`Error
|
|
771
|
+
_loggerProxy.default.error(`Error connecting to RTD websocket ${error}`, {
|
|
657
772
|
module: _constants.CC_FILE,
|
|
658
773
|
method: _constants.METHODS.CONNECT_WEBSOCKET
|
|
659
774
|
});
|
|
660
775
|
});
|
|
661
776
|
}
|
|
662
|
-
if (this.agentConfig.webRtcEnabled && this.agentConfig.loginVoiceOptions.includes(_types.LoginOption.BROWSER)) {
|
|
777
|
+
if (this.agentConfig.webRtcEnabled && this.agentConfig.loginVoiceOptions.includes(_types.LoginOption.BROWSER) && !this.isWebRTCRegistrationDisabled()) {
|
|
663
778
|
try {
|
|
664
779
|
await this.$webex.internal.mercury.connect();
|
|
665
780
|
_loggerProxy.default.log('Authentication: webex.internal.mercury.connect successful', {
|
|
@@ -672,9 +787,19 @@ class ContactCenter extends _webexCore.WebexPlugin {
|
|
|
672
787
|
method: _constants.METHODS.CONNECT_WEBSOCKET
|
|
673
788
|
});
|
|
674
789
|
}
|
|
790
|
+
} else if (this.isWebRTCRegistrationDisabled()) {
|
|
791
|
+
_loggerProxy.default.info('Skipping Mobius registration because disableWebRTCRegistration is enabled', {
|
|
792
|
+
module: _constants.CC_FILE,
|
|
793
|
+
method: _constants.METHODS.CONNECT_WEBSOCKET
|
|
794
|
+
});
|
|
675
795
|
}
|
|
676
796
|
if (this.$config && this.$config.allowAutomatedRelogin) {
|
|
677
797
|
await this.silentRelogin();
|
|
798
|
+
} else {
|
|
799
|
+
_loggerProxy.default.log('Skipping silent relogin: allowAutomatedRelogin is disabled', {
|
|
800
|
+
module: _constants.CC_FILE,
|
|
801
|
+
method: _constants.METHODS.CONNECT_WEBSOCKET
|
|
802
|
+
});
|
|
678
803
|
}
|
|
679
804
|
return this.agentConfig;
|
|
680
805
|
} catch (error) {
|
|
@@ -715,30 +840,37 @@ class ContactCenter extends _webexCore.WebexPlugin {
|
|
|
715
840
|
* ```
|
|
716
841
|
*/
|
|
717
842
|
async stationLogin(data) {
|
|
718
|
-
|
|
843
|
+
const loggerContext = {
|
|
719
844
|
module: _constants.CC_FILE,
|
|
720
845
|
method: _constants.METHODS.STATION_LOGIN
|
|
721
|
-
}
|
|
846
|
+
};
|
|
722
847
|
try {
|
|
848
|
+
_loggerProxy.default.log(`Starting agent station login | loginOption: ${data?.loginOption} teamId: ${data?.teamId}`, loggerContext);
|
|
723
849
|
this.metricsManager.timeEvent([_constants4.METRIC_EVENT_NAMES.STATION_LOGIN_SUCCESS, _constants4.METRIC_EVENT_NAMES.STATION_LOGIN_FAILED]);
|
|
724
850
|
const dialPlanEntries = this.agentConfig?.dialPlan?.dialPlanEntity ?? [];
|
|
725
|
-
if (data.loginOption === _types.LoginOption.AGENT_DN
|
|
726
|
-
|
|
727
|
-
|
|
728
|
-
|
|
729
|
-
|
|
730
|
-
|
|
731
|
-
|
|
732
|
-
|
|
733
|
-
|
|
851
|
+
if (data.loginOption === _types.LoginOption.AGENT_DN) {
|
|
852
|
+
_loggerProxy.default.log(`Validating dial number | dialPlanEnabled: ${!!this.agentConfig?.dialPlan} | dialPlanEntryCount: ${dialPlanEntries.length}`, loggerContext);
|
|
853
|
+
if (!(0, _Utils.isValidDialNumber)(data.dialNumber, dialPlanEntries)) {
|
|
854
|
+
_loggerProxy.default.log(`Dial number validation failed | dialNumber: ${data.dialNumber} | dialPlanEntryCount: ${dialPlanEntries.length}`, loggerContext);
|
|
855
|
+
const error = new Error('INVALID_DIAL_NUMBER');
|
|
856
|
+
// @ts-ignore - adding custom key to the error object
|
|
857
|
+
error.details = {
|
|
858
|
+
data: {
|
|
859
|
+
reason: 'INVALID_DIAL_NUMBER'
|
|
860
|
+
}
|
|
861
|
+
};
|
|
862
|
+
throw error;
|
|
863
|
+
}
|
|
734
864
|
}
|
|
865
|
+
const deviceId = this.getDeviceId(data.loginOption, data.dialNumber);
|
|
735
866
|
const loginResponse = await this.services.agent.stationLogin({
|
|
736
867
|
data: {
|
|
737
|
-
|
|
868
|
+
// BROWSER DN must be webrtc-{agentId} so VPOP/RTMS do not treat a bare UUID as PSTN.
|
|
869
|
+
dialNumber: data.loginOption === _types.LoginOption.BROWSER ? deviceId : data.dialNumber,
|
|
738
870
|
teamId: data.teamId,
|
|
739
871
|
deviceType: data.loginOption,
|
|
740
872
|
isExtension: data.loginOption === _types.LoginOption.EXTENSION,
|
|
741
|
-
deviceId
|
|
873
|
+
deviceId,
|
|
742
874
|
roles: [_constants3.AGENT],
|
|
743
875
|
teamName: _constants.EMPTY_STRING,
|
|
744
876
|
siteId: _constants.EMPTY_STRING,
|
|
@@ -746,8 +878,13 @@ class ContactCenter extends _webexCore.WebexPlugin {
|
|
|
746
878
|
auxCodeId: _constants.EMPTY_STRING
|
|
747
879
|
}
|
|
748
880
|
});
|
|
749
|
-
if (this.agentConfig.webRtcEnabled && data.loginOption === _types.LoginOption.BROWSER) {
|
|
881
|
+
if (this.agentConfig.webRtcEnabled && data.loginOption === _types.LoginOption.BROWSER && !this.isWebRTCRegistrationDisabled()) {
|
|
750
882
|
await this.webCallingService.registerWebCallingLine();
|
|
883
|
+
} else if (this.agentConfig.webRtcEnabled && data.loginOption === _types.LoginOption.BROWSER && this.isWebRTCRegistrationDisabled()) {
|
|
884
|
+
_loggerProxy.default.info('Skipping web calling line registration because disableWebRTCRegistration is enabled', {
|
|
885
|
+
module: _constants.CC_FILE,
|
|
886
|
+
method: _constants.METHODS.STATION_LOGIN
|
|
887
|
+
});
|
|
751
888
|
}
|
|
752
889
|
const resp = await loginResponse;
|
|
753
890
|
const {
|
|
@@ -766,6 +903,13 @@ class ContactCenter extends _webexCore.WebexPlugin {
|
|
|
766
903
|
notifsTrackingId: resp.trackingId
|
|
767
904
|
};
|
|
768
905
|
this.webCallingService.setLoginOption(data.loginOption);
|
|
906
|
+
if (this.agentConfig) {
|
|
907
|
+
this.agentConfig.deviceType = data.loginOption;
|
|
908
|
+
if (data.loginOption === _types.LoginOption.AGENT_DN || data.loginOption === _types.LoginOption.EXTENSION) {
|
|
909
|
+
this.agentConfig.defaultDn = data.dialNumber;
|
|
910
|
+
this.agentConfig.dn = data.dialNumber;
|
|
911
|
+
}
|
|
912
|
+
}
|
|
769
913
|
this.metricsManager.trackEvent(_constants4.METRIC_EVENT_NAMES.STATION_LOGIN_SUCCESS, {
|
|
770
914
|
..._MetricsManager.default.getCommonTrackingFieldForAQMResponse(resp),
|
|
771
915
|
loginType: data.loginOption,
|
|
@@ -778,6 +922,7 @@ class ContactCenter extends _webexCore.WebexPlugin {
|
|
|
778
922
|
method: _constants.METHODS.STATION_LOGIN,
|
|
779
923
|
trackingId: resp.trackingId
|
|
780
924
|
});
|
|
925
|
+
await this.ensureWxAppPostStationLogin();
|
|
781
926
|
return response;
|
|
782
927
|
} catch (error) {
|
|
783
928
|
const failure = error.details;
|
|
@@ -832,6 +977,7 @@ class ContactCenter extends _webexCore.WebexPlugin {
|
|
|
832
977
|
if (this.webCallingService) {
|
|
833
978
|
this.webCallingService.deregisterWebCallingLine();
|
|
834
979
|
}
|
|
980
|
+
await this.teardownWxAppLocalState();
|
|
835
981
|
_loggerProxy.default.log(`Agent station logout completed successfully`, {
|
|
836
982
|
module: _constants.CC_FILE,
|
|
837
983
|
method: _constants.METHODS.STATION_LOGOUT,
|
|
@@ -1071,6 +1217,490 @@ class ContactCenter extends _webexCore.WebexPlugin {
|
|
|
1071
1217
|
}
|
|
1072
1218
|
};
|
|
1073
1219
|
|
|
1220
|
+
/**
|
|
1221
|
+
* Checks whether Mobius/WebRTC registration should be skipped by config
|
|
1222
|
+
* @returns {boolean} True when browser WebRTC registration is disabled
|
|
1223
|
+
* @private
|
|
1224
|
+
*/
|
|
1225
|
+
isWebRTCRegistrationDisabled() {
|
|
1226
|
+
return this.$config?.disableWebRTCRegistration === true;
|
|
1227
|
+
}
|
|
1228
|
+
|
|
1229
|
+
/**
|
|
1230
|
+
* Validates contact-center plugin configuration before service initialization
|
|
1231
|
+
* @private
|
|
1232
|
+
*/
|
|
1233
|
+
validatePluginConfig() {
|
|
1234
|
+
if (this.$config?.disableWebRTCRegistration === true && this.$config?.allowMultiLogin === false) {
|
|
1235
|
+
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.');
|
|
1236
|
+
}
|
|
1237
|
+
}
|
|
1238
|
+
|
|
1239
|
+
/**
|
|
1240
|
+
* Whether wxApp thick-client answer is enabled for this SDK instance.
|
|
1241
|
+
* @public
|
|
1242
|
+
*/
|
|
1243
|
+
isWxBetterTogetherEnabled() {
|
|
1244
|
+
return this.$config?.enableWxBetterTogether === true;
|
|
1245
|
+
}
|
|
1246
|
+
|
|
1247
|
+
/**
|
|
1248
|
+
* Current station login option (Extension, Dial Number, or Browser/Desktop).
|
|
1249
|
+
* Prefer webCallingService — updated on every stationLogin before wxApp hooks run.
|
|
1250
|
+
* @private
|
|
1251
|
+
*/
|
|
1252
|
+
getCurrentStationLoginOption() {
|
|
1253
|
+
return this.webCallingService?.loginOption ?? this.agentConfig?.deviceType;
|
|
1254
|
+
}
|
|
1255
|
+
|
|
1256
|
+
/**
|
|
1257
|
+
* wxApp thick-client answer is supported for Extension and Dial Number station login only —
|
|
1258
|
+
* not Browser/Desktop (WebRTC) login.
|
|
1259
|
+
* @private
|
|
1260
|
+
*/
|
|
1261
|
+
assertWxAppStationLoginSupportedForEnable() {
|
|
1262
|
+
const loginOption = this.getCurrentStationLoginOption();
|
|
1263
|
+
if (loginOption !== _types.LoginOption.EXTENSION && loginOption !== _types.LoginOption.AGENT_DN) {
|
|
1264
|
+
throw new Error('setManageWebexCallingInWxcc requires EXTENSION or AGENT_DN station login. Complete station login before enabling.');
|
|
1265
|
+
}
|
|
1266
|
+
}
|
|
1267
|
+
|
|
1268
|
+
/**
|
|
1269
|
+
* Clears runtime wxApp config after logout/deregister so stale flags do not apply on relogin.
|
|
1270
|
+
* @private
|
|
1271
|
+
*/
|
|
1272
|
+
resetEnableWxBetterTogetherConfig() {
|
|
1273
|
+
if (this.$config) {
|
|
1274
|
+
this.$config.enableWxBetterTogether = false;
|
|
1275
|
+
}
|
|
1276
|
+
this.taskManager.applyEnableWxBetterTogether(false);
|
|
1277
|
+
}
|
|
1278
|
+
|
|
1279
|
+
/**
|
|
1280
|
+
* Runtime enable/disable for wxApp Better Together (toast suppression + Mercury mute sync).
|
|
1281
|
+
*
|
|
1282
|
+
* **Phase 1 (WXCC-6026 / MMT): NOT part of the public host contract.**
|
|
1283
|
+
* Hosts must set `webexConfig.cc.enableWxBetterTogether` before `webex.init()` / `cc.register()`.
|
|
1284
|
+
* To change the flag after the SDK is initialized, re-init the SDK with the updated config.
|
|
1285
|
+
*
|
|
1286
|
+
* **Supported public read API:** {@link isWxBetterTogetherEnabled}.
|
|
1287
|
+
* **Supported telephony API:** unified `task.accept()`, `task.decline()`, `task.toggleMute()`,
|
|
1288
|
+
* `task.transmitDtmf()` — SDK routes wxApp calls internally when the init flag is active.
|
|
1289
|
+
*
|
|
1290
|
+
* **Production lifecycle does not call this method.** Station login, silent relogin, logout,
|
|
1291
|
+
* and deregister use {@link ensureWxAppPostStationLogin} and {@link teardownWxAppLocalState}
|
|
1292
|
+
* (usersub publish + Mercury subscribe/unsubscribe based on the init flag).
|
|
1293
|
+
*
|
|
1294
|
+
* This setter remains as a **private implementation** for Phase 2 runtime toggle and unit tests.
|
|
1295
|
+
* It updates `$config.enableWxBetterTogether`, TaskManager flags, cross-client usersub
|
|
1296
|
+
* (`answer-calls-on-wxcc`), and Mercury mute sync; rolls back config on publish/connect failure.
|
|
1297
|
+
*
|
|
1298
|
+
* @param enabled - `true` to enable wxApp answer + usersub suppression; `false` to disable and tear down.
|
|
1299
|
+
* @throws When enabling without login, on unsupported BROWSER station login, or when usersub/Mercury init fails.
|
|
1300
|
+
* @internal
|
|
1301
|
+
* @see enableWxBetterTogether (CCPluginConfig init flag)
|
|
1302
|
+
* @see ensureWxAppPostStationLogin
|
|
1303
|
+
* @see teardownWxAppLocalState
|
|
1304
|
+
*/
|
|
1305
|
+
async setManageWebexCallingInWxcc(enabled) {
|
|
1306
|
+
if (enabled && !this.$webex.internal.device?.userId) {
|
|
1307
|
+
throw new Error('Cannot publish answer-calls-on-wxcc: user is not logged in');
|
|
1308
|
+
}
|
|
1309
|
+
if (enabled) {
|
|
1310
|
+
this.assertWxAppStationLoginSupportedForEnable();
|
|
1311
|
+
}
|
|
1312
|
+
const previousEnabled = this.isWxBetterTogetherEnabled();
|
|
1313
|
+
if (this.$config) {
|
|
1314
|
+
this.$config.enableWxBetterTogether = enabled;
|
|
1315
|
+
}
|
|
1316
|
+
this.taskManager.applyEnableWxBetterTogether(enabled);
|
|
1317
|
+
let publishedEnable = false;
|
|
1318
|
+
try {
|
|
1319
|
+
if (enabled) {
|
|
1320
|
+
await this.ensureWxAppMercuryAndSubscribe();
|
|
1321
|
+
await this.publishAnswerOnWebexCrossClientState(true);
|
|
1322
|
+
publishedEnable = true;
|
|
1323
|
+
this.taskManager.syncWxAppMuteFromCallDetailsForAllTasks();
|
|
1324
|
+
} else {
|
|
1325
|
+
await this.publishAnswerOnWebexCrossClientState(false);
|
|
1326
|
+
this.wxAppTelephonyMercurySync.unsubscribe();
|
|
1327
|
+
await this.releaseWxAppMercuryResources();
|
|
1328
|
+
}
|
|
1329
|
+
} catch (error) {
|
|
1330
|
+
if (publishedEnable) {
|
|
1331
|
+
await this.revertWxAppCrossClientPublish();
|
|
1332
|
+
} else if (enabled) {
|
|
1333
|
+
this.wxAppTelephonyMercurySync.unsubscribe();
|
|
1334
|
+
await this.releaseWxAppMercuryResources();
|
|
1335
|
+
}
|
|
1336
|
+
if (this.$config) {
|
|
1337
|
+
this.$config.enableWxBetterTogether = previousEnabled;
|
|
1338
|
+
}
|
|
1339
|
+
this.taskManager.applyEnableWxBetterTogether(previousEnabled);
|
|
1340
|
+
throw error;
|
|
1341
|
+
}
|
|
1342
|
+
}
|
|
1343
|
+
getWxAppTelephonyTaskType() {
|
|
1344
|
+
const loginOption = this.getCurrentStationLoginOption();
|
|
1345
|
+
if (loginOption === _types.LoginOption.BROWSER) {
|
|
1346
|
+
return 'WebRTC';
|
|
1347
|
+
}
|
|
1348
|
+
if (loginOption === _types.LoginOption.EXTENSION || loginOption === _types.LoginOption.AGENT_DN) {
|
|
1349
|
+
return 'Voice';
|
|
1350
|
+
}
|
|
1351
|
+
return 'unknown';
|
|
1352
|
+
}
|
|
1353
|
+
async ensureWxAppPostStationLogin() {
|
|
1354
|
+
const loginOption = this.getCurrentStationLoginOption();
|
|
1355
|
+
const flagEnabled = this.isWxBetterTogetherEnabled();
|
|
1356
|
+
const telephonyTaskType = this.getWxAppTelephonyTaskType();
|
|
1357
|
+
if (loginOption === _types.LoginOption.BROWSER) {
|
|
1358
|
+
if (flagEnabled) {
|
|
1359
|
+
(0, _wxAppDiagnosticLogging.logWxAppSessionReadiness)({
|
|
1360
|
+
enableWxBetterTogether: true,
|
|
1361
|
+
loginOption,
|
|
1362
|
+
wxAppHooksApplied: false,
|
|
1363
|
+
usersubPublished: false,
|
|
1364
|
+
mercurySubscribed: false,
|
|
1365
|
+
telephonyTaskType,
|
|
1366
|
+
skipReason: 'unsupported_browser_login'
|
|
1367
|
+
});
|
|
1368
|
+
this.metricsManager.trackEvent(_constants4.METRIC_EVENT_NAMES.WXAPP_SESSION_SKIPPED, {
|
|
1369
|
+
loginOption,
|
|
1370
|
+
enableWxBetterTogether: true,
|
|
1371
|
+
skipReason: 'unsupported_browser_login'
|
|
1372
|
+
}, ['operational', 'behavioral']);
|
|
1373
|
+
}
|
|
1374
|
+
return;
|
|
1375
|
+
}
|
|
1376
|
+
let publishedEnable = false;
|
|
1377
|
+
let wxAppInitStage = 'mercury';
|
|
1378
|
+
try {
|
|
1379
|
+
if (flagEnabled) {
|
|
1380
|
+
this.metricsManager.timeEvent([_constants4.METRIC_EVENT_NAMES.WXAPP_SESSION_INIT_SUCCESS, _constants4.METRIC_EVENT_NAMES.WXAPP_SESSION_INIT_FAILED]);
|
|
1381
|
+
await this.ensureWxAppMercuryAndSubscribe();
|
|
1382
|
+
wxAppInitStage = 'publish';
|
|
1383
|
+
await this.publishAnswerOnWebexCrossClientState(true);
|
|
1384
|
+
publishedEnable = true;
|
|
1385
|
+
this.taskManager.syncWxAppMuteFromCallDetailsForAllTasks();
|
|
1386
|
+
const mercurySubscribed = this.wxAppTelephonyMercurySync.isSubscribed();
|
|
1387
|
+
const usersubPublished = this.webexCrossClientService.isAnswerCallsStateActive();
|
|
1388
|
+
(0, _wxAppDiagnosticLogging.logWxAppSessionReadiness)({
|
|
1389
|
+
enableWxBetterTogether: true,
|
|
1390
|
+
loginOption,
|
|
1391
|
+
wxAppHooksApplied: true,
|
|
1392
|
+
usersubPublished,
|
|
1393
|
+
mercurySubscribed,
|
|
1394
|
+
telephonyTaskType
|
|
1395
|
+
});
|
|
1396
|
+
const sessionInitReady = mercurySubscribed && usersubPublished;
|
|
1397
|
+
if (sessionInitReady) {
|
|
1398
|
+
this.metricsManager.trackEvent(_constants4.METRIC_EVENT_NAMES.WXAPP_SESSION_INIT_SUCCESS, {
|
|
1399
|
+
loginOption,
|
|
1400
|
+
enableWxBetterTogether: true
|
|
1401
|
+
}, ['operational', 'behavioral']);
|
|
1402
|
+
} else {
|
|
1403
|
+
this.metricsManager.trackEvent(_constants4.METRIC_EVENT_NAMES.WXAPP_SESSION_INIT_FAILED, {
|
|
1404
|
+
loginOption,
|
|
1405
|
+
enableWxBetterTogether: true,
|
|
1406
|
+
skipReason: !usersubPublished ? 'usersub_not_published' : 'mercury_not_subscribed'
|
|
1407
|
+
}, ['operational', 'behavioral']);
|
|
1408
|
+
}
|
|
1409
|
+
} else {
|
|
1410
|
+
await this.ensureWxAppDeviceRegistered();
|
|
1411
|
+
await this.publishAnswerOnWebexCrossClientState(false, {
|
|
1412
|
+
force: true
|
|
1413
|
+
});
|
|
1414
|
+
this.webexCrossClientService.teardown();
|
|
1415
|
+
this.wxAppTelephonyMercurySync.unsubscribe();
|
|
1416
|
+
await this.releaseWxAppMercuryResources();
|
|
1417
|
+
(0, _wxAppDiagnosticLogging.logWxAppSessionReadiness)({
|
|
1418
|
+
enableWxBetterTogether: false,
|
|
1419
|
+
loginOption,
|
|
1420
|
+
wxAppHooksApplied: true,
|
|
1421
|
+
usersubPublished: false,
|
|
1422
|
+
mercurySubscribed: false,
|
|
1423
|
+
telephonyTaskType,
|
|
1424
|
+
skipReason: 'flag_disabled'
|
|
1425
|
+
});
|
|
1426
|
+
this.metricsManager.trackEvent(_constants4.METRIC_EVENT_NAMES.WXAPP_SESSION_SKIPPED, {
|
|
1427
|
+
loginOption,
|
|
1428
|
+
enableWxBetterTogether: false,
|
|
1429
|
+
skipReason: 'flag_disabled'
|
|
1430
|
+
}, ['operational', 'behavioral']);
|
|
1431
|
+
}
|
|
1432
|
+
} catch (error) {
|
|
1433
|
+
_loggerProxy.default.error(`Failed to initialize wxApp post-station-login: ${error}`, {
|
|
1434
|
+
module: _constants.CC_FILE,
|
|
1435
|
+
method: _constants.METHODS.STATION_LOGIN
|
|
1436
|
+
});
|
|
1437
|
+
if (flagEnabled) {
|
|
1438
|
+
const sessionInitFailureReason = wxAppInitStage === 'mercury' ? 'mercury_subscribe_failed' : 'publish_failed';
|
|
1439
|
+
this.metricsManager.trackEvent(_constants4.METRIC_EVENT_NAMES.WXAPP_SESSION_INIT_FAILED, {
|
|
1440
|
+
loginOption,
|
|
1441
|
+
enableWxBetterTogether: true,
|
|
1442
|
+
skipReason: sessionInitFailureReason,
|
|
1443
|
+
error: error instanceof Error ? error.toString() : String(error)
|
|
1444
|
+
}, ['operational', 'behavioral']);
|
|
1445
|
+
(0, _wxAppDiagnosticLogging.logWxAppSessionReadiness)({
|
|
1446
|
+
enableWxBetterTogether: true,
|
|
1447
|
+
loginOption,
|
|
1448
|
+
wxAppHooksApplied: false,
|
|
1449
|
+
usersubPublished: publishedEnable && this.webexCrossClientService.isAnswerCallsStateActive(),
|
|
1450
|
+
mercurySubscribed: this.wxAppTelephonyMercurySync.isSubscribed(),
|
|
1451
|
+
telephonyTaskType,
|
|
1452
|
+
skipReason: sessionInitFailureReason
|
|
1453
|
+
});
|
|
1454
|
+
if (publishedEnable) {
|
|
1455
|
+
await this.revertWxAppCrossClientPublish();
|
|
1456
|
+
} else {
|
|
1457
|
+
this.wxAppTelephonyMercurySync.unsubscribe();
|
|
1458
|
+
await this.releaseWxAppMercuryResources();
|
|
1459
|
+
}
|
|
1460
|
+
this.resetEnableWxBetterTogetherConfig();
|
|
1461
|
+
} else {
|
|
1462
|
+
this.scheduleForcedFalsePublishRetry();
|
|
1463
|
+
}
|
|
1464
|
+
}
|
|
1465
|
+
}
|
|
1466
|
+
clearWxAppFalsePublishRetryTimer() {
|
|
1467
|
+
if (this.wxAppFalsePublishRetryTimer) {
|
|
1468
|
+
clearTimeout(this.wxAppFalsePublishRetryTimer);
|
|
1469
|
+
this.wxAppFalsePublishRetryTimer = undefined;
|
|
1470
|
+
}
|
|
1471
|
+
}
|
|
1472
|
+
scheduleForcedFalsePublishRetry(retryAttempt = 0) {
|
|
1473
|
+
this.scheduleFalsePublishRetry(retryAttempt, {
|
|
1474
|
+
requireDisabled: true
|
|
1475
|
+
});
|
|
1476
|
+
}
|
|
1477
|
+
|
|
1478
|
+
/**
|
|
1479
|
+
* Retries compensating false publish after rollback failure, regardless of enabled flag.
|
|
1480
|
+
* @private
|
|
1481
|
+
*/
|
|
1482
|
+
scheduleCompensatingFalsePublishRetry(retryAttempt = 0) {
|
|
1483
|
+
this.scheduleFalsePublishRetry(retryAttempt);
|
|
1484
|
+
}
|
|
1485
|
+
scheduleFalsePublishRetry(retryAttempt = 0, options = {}) {
|
|
1486
|
+
if (retryAttempt >= ContactCenter.WXAPP_FALSE_PUBLISH_MAX_RETRIES) {
|
|
1487
|
+
return;
|
|
1488
|
+
}
|
|
1489
|
+
if (options?.requireDisabled && this.isWxBetterTogetherEnabled()) {
|
|
1490
|
+
return;
|
|
1491
|
+
}
|
|
1492
|
+
this.clearWxAppFalsePublishRetryTimer();
|
|
1493
|
+
this.wxAppFalsePublishRetryTimer = setTimeout(async () => {
|
|
1494
|
+
this.wxAppFalsePublishRetryTimer = undefined;
|
|
1495
|
+
if (options?.requireDisabled && this.isWxBetterTogetherEnabled()) {
|
|
1496
|
+
return;
|
|
1497
|
+
}
|
|
1498
|
+
if (!options?.requireDisabled && this.isWxBetterTogetherEnabled() && this.webexCrossClientService.isAnswerCallsStateActive()) {
|
|
1499
|
+
return;
|
|
1500
|
+
}
|
|
1501
|
+
try {
|
|
1502
|
+
await this.ensureWxAppDeviceRegistered();
|
|
1503
|
+
await this.publishAnswerOnWebexCrossClientState(false, {
|
|
1504
|
+
force: true
|
|
1505
|
+
});
|
|
1506
|
+
this.webexCrossClientService.teardown();
|
|
1507
|
+
this.wxAppTelephonyMercurySync.unsubscribe();
|
|
1508
|
+
await this.releaseWxAppMercuryResources();
|
|
1509
|
+
} catch (retryError) {
|
|
1510
|
+
_loggerProxy.default.error(`Failed to retry forced answer-calls-on-wxcc false publish: ${retryError}`, {
|
|
1511
|
+
module: _constants.CC_FILE,
|
|
1512
|
+
method: _constants.METHODS.SET_MANAGE_WEBEX_CALLING_IN_WXCC
|
|
1513
|
+
});
|
|
1514
|
+
this.scheduleFalsePublishRetry(retryAttempt + 1, options);
|
|
1515
|
+
}
|
|
1516
|
+
}, ContactCenter.WXAPP_FALSE_PUBLISH_RETRY_DELAY_MS);
|
|
1517
|
+
}
|
|
1518
|
+
|
|
1519
|
+
/**
|
|
1520
|
+
* Best-effort rollback when usersub true was published but wxApp setup did not complete.
|
|
1521
|
+
* @private
|
|
1522
|
+
*/
|
|
1523
|
+
async revertWxAppCrossClientPublish() {
|
|
1524
|
+
try {
|
|
1525
|
+
await this.publishAnswerOnWebexCrossClientState(false, {
|
|
1526
|
+
force: true
|
|
1527
|
+
});
|
|
1528
|
+
} catch (error) {
|
|
1529
|
+
_loggerProxy.default.error(`Failed to publish compensating answer-calls-on-wxcc false during wxApp rollback: ${error}`, {
|
|
1530
|
+
module: _constants.CC_FILE,
|
|
1531
|
+
method: _constants.METHODS.SET_MANAGE_WEBEX_CALLING_IN_WXCC
|
|
1532
|
+
});
|
|
1533
|
+
this.scheduleCompensatingFalsePublishRetry();
|
|
1534
|
+
}
|
|
1535
|
+
this.webexCrossClientService.teardown();
|
|
1536
|
+
this.wxAppTelephonyMercurySync.unsubscribe();
|
|
1537
|
+
await this.releaseWxAppMercuryResources();
|
|
1538
|
+
}
|
|
1539
|
+
async ensureWxAppDeviceRegistered() {
|
|
1540
|
+
const device = this.$webex.internal.device;
|
|
1541
|
+
if (device && !device.registered && device.register) {
|
|
1542
|
+
await device.register();
|
|
1543
|
+
this.wxAppDeviceRegisteredByCc = true;
|
|
1544
|
+
_loggerProxy.default.log('WxApp: device registered for cross-client publish', {
|
|
1545
|
+
module: _constants.CC_FILE,
|
|
1546
|
+
method: _constants.METHODS.ENSURE_WXAPP_MERCURY_CONNECTED
|
|
1547
|
+
});
|
|
1548
|
+
}
|
|
1549
|
+
}
|
|
1550
|
+
async ensureWxAppMercuryConnected() {
|
|
1551
|
+
const mercury = this.$webex.internal.mercury;
|
|
1552
|
+
await this.ensureWxAppDeviceRegistered();
|
|
1553
|
+
if (mercury && !mercury.connected) {
|
|
1554
|
+
await mercury.connect();
|
|
1555
|
+
this.wxAppMercuryConnectedByCc = true;
|
|
1556
|
+
_loggerProxy.default.log('WxApp mute sync: mercury connected', {
|
|
1557
|
+
module: _constants.CC_FILE,
|
|
1558
|
+
method: _constants.METHODS.ENSURE_WXAPP_MERCURY_CONNECTED
|
|
1559
|
+
});
|
|
1560
|
+
}
|
|
1561
|
+
}
|
|
1562
|
+
|
|
1563
|
+
/**
|
|
1564
|
+
* Disconnects Mercury and unregisters the device when wxApp mute sync opened them.
|
|
1565
|
+
* @private
|
|
1566
|
+
*/
|
|
1567
|
+
async releaseWxAppMercuryResources() {
|
|
1568
|
+
const mercury = this.$webex.internal.mercury;
|
|
1569
|
+
const device = this.$webex.internal.device;
|
|
1570
|
+
if (this.wxAppMercuryConnectedByCc && mercury?.connected) {
|
|
1571
|
+
try {
|
|
1572
|
+
await mercury.disconnect();
|
|
1573
|
+
this.wxAppMercuryConnectedByCc = false;
|
|
1574
|
+
_loggerProxy.default.log('WxApp mute sync: mercury disconnected', {
|
|
1575
|
+
module: _constants.CC_FILE,
|
|
1576
|
+
method: _constants.METHODS.ENSURE_WXAPP_MERCURY_CONNECTED
|
|
1577
|
+
});
|
|
1578
|
+
} catch (error) {
|
|
1579
|
+
_loggerProxy.default.error(`Failed to disconnect wxApp Mercury: ${error}`, {
|
|
1580
|
+
module: _constants.CC_FILE,
|
|
1581
|
+
method: _constants.METHODS.ENSURE_WXAPP_MERCURY_CONNECTED
|
|
1582
|
+
});
|
|
1583
|
+
}
|
|
1584
|
+
}
|
|
1585
|
+
if (this.wxAppDeviceRegisteredByCc && device?.registered && device.unregister) {
|
|
1586
|
+
try {
|
|
1587
|
+
// @ts-ignore
|
|
1588
|
+
await device.unregister();
|
|
1589
|
+
this.wxAppDeviceRegisteredByCc = false;
|
|
1590
|
+
_loggerProxy.default.log('WxApp mute sync: device unregistered', {
|
|
1591
|
+
module: _constants.CC_FILE,
|
|
1592
|
+
method: _constants.METHODS.ENSURE_WXAPP_MERCURY_CONNECTED
|
|
1593
|
+
});
|
|
1594
|
+
} catch (error) {
|
|
1595
|
+
_loggerProxy.default.error(`Failed to unregister wxApp device: ${error}`, {
|
|
1596
|
+
module: _constants.CC_FILE,
|
|
1597
|
+
method: _constants.METHODS.ENSURE_WXAPP_MERCURY_CONNECTED
|
|
1598
|
+
});
|
|
1599
|
+
}
|
|
1600
|
+
} else if (this.wxAppDeviceRegisteredByCc) {
|
|
1601
|
+
this.wxAppDeviceRegisteredByCc = false;
|
|
1602
|
+
}
|
|
1603
|
+
}
|
|
1604
|
+
|
|
1605
|
+
/**
|
|
1606
|
+
* Clears wxApp runtime state and feature-owned resources. Publish failures are logged;
|
|
1607
|
+
* optional rethrow for deregister when callers need to surface usersub errors.
|
|
1608
|
+
* @private
|
|
1609
|
+
*/
|
|
1610
|
+
async teardownWxAppLocalState(options) {
|
|
1611
|
+
this.clearWxAppFalsePublishRetryTimer();
|
|
1612
|
+
let publishError;
|
|
1613
|
+
try {
|
|
1614
|
+
const shouldForceFalsePublish = this.isWxBetterTogetherEnabled() || this.webexCrossClientService.isAnswerCallsStateActive();
|
|
1615
|
+
await this.publishAnswerOnWebexCrossClientState(false, {
|
|
1616
|
+
force: shouldForceFalsePublish
|
|
1617
|
+
});
|
|
1618
|
+
} catch (error) {
|
|
1619
|
+
publishError = error;
|
|
1620
|
+
_loggerProxy.default.error(`Failed to publish answer-calls-on-wxcc false during wxApp teardown: ${error}`, {
|
|
1621
|
+
module: _constants.CC_FILE,
|
|
1622
|
+
method: _constants.METHODS.SET_MANAGE_WEBEX_CALLING_IN_WXCC
|
|
1623
|
+
});
|
|
1624
|
+
}
|
|
1625
|
+
this.webexCrossClientService.teardown();
|
|
1626
|
+
this.wxAppTelephonyMercurySync.unsubscribe();
|
|
1627
|
+
await this.releaseWxAppMercuryResources();
|
|
1628
|
+
if (options?.clearInitFlag) {
|
|
1629
|
+
this.resetEnableWxBetterTogetherConfig();
|
|
1630
|
+
}
|
|
1631
|
+
if (publishError) {
|
|
1632
|
+
this.scheduleCompensatingFalsePublishRetry();
|
|
1633
|
+
}
|
|
1634
|
+
if (options?.rethrowPublishError && publishError) {
|
|
1635
|
+
throw publishError;
|
|
1636
|
+
}
|
|
1637
|
+
return {
|
|
1638
|
+
publishError: publishError ?? undefined
|
|
1639
|
+
};
|
|
1640
|
+
}
|
|
1641
|
+
async ensureWxAppMercuryAndSubscribe() {
|
|
1642
|
+
if (!this.isWxBetterTogetherEnabled()) {
|
|
1643
|
+
return;
|
|
1644
|
+
}
|
|
1645
|
+
if (this.getCurrentStationLoginOption() === _types.LoginOption.BROWSER) {
|
|
1646
|
+
return;
|
|
1647
|
+
}
|
|
1648
|
+
const agentId = this.agentConfig?.agentId;
|
|
1649
|
+
if (!agentId) {
|
|
1650
|
+
_loggerProxy.default.error('Cannot subscribe wxApp mute sync: agentId unavailable', {
|
|
1651
|
+
module: _constants.CC_FILE,
|
|
1652
|
+
method: _constants.METHODS.SYNC_WXAPP_MUTE_FROM_MERCURY
|
|
1653
|
+
});
|
|
1654
|
+
this.metricsManager.trackEvent(_constants4.METRIC_EVENT_NAMES.WXAPP_MERCURY_SUBSCRIBE_FAILED, {
|
|
1655
|
+
error: 'agentId unavailable'
|
|
1656
|
+
}, ['operational', 'behavioral']);
|
|
1657
|
+
return;
|
|
1658
|
+
}
|
|
1659
|
+
try {
|
|
1660
|
+
await this.ensureWxAppMercuryConnected();
|
|
1661
|
+
this.wxAppTelephonyMercurySync.subscribe(agentId, (callId, muted) => {
|
|
1662
|
+
this.taskManager.applyWxAppMuteStateFromSync(callId, muted);
|
|
1663
|
+
});
|
|
1664
|
+
} catch (error) {
|
|
1665
|
+
_loggerProxy.default.error(`Failed to ensure wxApp Mercury mute sync: ${error}`, {
|
|
1666
|
+
module: _constants.CC_FILE,
|
|
1667
|
+
method: _constants.METHODS.SYNC_WXAPP_MUTE_FROM_MERCURY
|
|
1668
|
+
});
|
|
1669
|
+
this.metricsManager.trackEvent(_constants4.METRIC_EVENT_NAMES.WXAPP_MERCURY_SUBSCRIBE_FAILED, {
|
|
1670
|
+
error: error instanceof Error ? error.toString() : String(error)
|
|
1671
|
+
}, ['operational', 'behavioral']);
|
|
1672
|
+
this.wxAppTelephonyMercurySync.unsubscribe();
|
|
1673
|
+
await this.releaseWxAppMercuryResources();
|
|
1674
|
+
throw error;
|
|
1675
|
+
}
|
|
1676
|
+
}
|
|
1677
|
+
async publishAnswerOnWebexCrossClientState(enable, options) {
|
|
1678
|
+
if (enable && !this.isWxBetterTogetherEnabled()) {
|
|
1679
|
+
return;
|
|
1680
|
+
}
|
|
1681
|
+
if (!enable && !options?.force && !this.webexCrossClientService.isAnswerCallsStateActive()) {
|
|
1682
|
+
return;
|
|
1683
|
+
}
|
|
1684
|
+
const userId = this.$webex.internal.device?.userId;
|
|
1685
|
+
if (!userId) {
|
|
1686
|
+
if (enable && this.isWxBetterTogetherEnabled()) {
|
|
1687
|
+
this.metricsManager.trackEvent(_constants4.METRIC_EVENT_NAMES.WXAPP_USERSUB_PUBLISH_FAILED, {
|
|
1688
|
+
enableWxBetterTogether: true,
|
|
1689
|
+
skipReason: 'user_id_unavailable',
|
|
1690
|
+
error: 'User ID is unavailable for cross-client publish'
|
|
1691
|
+
}, ['operational', 'behavioral']);
|
|
1692
|
+
}
|
|
1693
|
+
return;
|
|
1694
|
+
}
|
|
1695
|
+
await this.webexCrossClientService.setManageWebexCallingInWxcc(enable, {
|
|
1696
|
+
userId,
|
|
1697
|
+
trackPublishMetrics: true
|
|
1698
|
+
});
|
|
1699
|
+
if (enable) {
|
|
1700
|
+
this.clearWxAppFalsePublishRetryTimer();
|
|
1701
|
+
}
|
|
1702
|
+
}
|
|
1703
|
+
|
|
1074
1704
|
/**
|
|
1075
1705
|
* Initializes event listeners for the Contact Center service
|
|
1076
1706
|
* Sets up handlers for connection state changes and other core events
|
|
@@ -1102,13 +1732,13 @@ class ContactCenter extends _webexCore.WebexPlugin {
|
|
|
1102
1732
|
async handleConnectionLost(msg) {
|
|
1103
1733
|
if (msg.isConnectionLost) {
|
|
1104
1734
|
// TODO: Emit an event saying connection is lost
|
|
1105
|
-
_loggerProxy.default.
|
|
1735
|
+
_loggerProxy.default.log('event=handleConnectionLost | Connection lost', {
|
|
1106
1736
|
module: _constants.CC_FILE,
|
|
1107
1737
|
method: _constants.METHODS.HANDLE_CONNECTION_LOST
|
|
1108
1738
|
});
|
|
1109
1739
|
} else if (msg.isSocketReconnected) {
|
|
1110
1740
|
// TODO: Emit an event saying connection is re-estabilished
|
|
1111
|
-
_loggerProxy.default.
|
|
1741
|
+
_loggerProxy.default.log('event=handleConnectionReconnect | Connection reconnected attempting to request silent relogin', {
|
|
1112
1742
|
module: _constants.CC_FILE,
|
|
1113
1743
|
method: _constants.METHODS.HANDLE_CONNECTION_LOST
|
|
1114
1744
|
});
|
|
@@ -1123,7 +1753,7 @@ class ContactCenter extends _webexCore.WebexPlugin {
|
|
|
1123
1753
|
* @private
|
|
1124
1754
|
*/
|
|
1125
1755
|
async silentRelogin() {
|
|
1126
|
-
_loggerProxy.default.
|
|
1756
|
+
_loggerProxy.default.log('Starting silent relogin process', {
|
|
1127
1757
|
module: _constants.CC_FILE,
|
|
1128
1758
|
method: _constants.METHODS.SILENT_RELOGIN
|
|
1129
1759
|
});
|
|
@@ -1145,7 +1775,7 @@ class ContactCenter extends _webexCore.WebexPlugin {
|
|
|
1145
1775
|
this.agentConfig.currentTeamId = reLoginResponse.data.teamId;
|
|
1146
1776
|
await this.handleDeviceType(deviceType, dn);
|
|
1147
1777
|
if (lastStateChangeReason === 'agent-wss-disconnect') {
|
|
1148
|
-
_loggerProxy.default.
|
|
1778
|
+
_loggerProxy.default.log('event=requestAutoStateChange | Requesting state change to available on socket reconnect', {
|
|
1149
1779
|
module: _constants.CC_FILE,
|
|
1150
1780
|
method: _constants.METHODS.SILENT_RELOGIN
|
|
1151
1781
|
});
|
|
@@ -1169,8 +1799,7 @@ class ContactCenter extends _webexCore.WebexPlugin {
|
|
|
1169
1799
|
}
|
|
1170
1800
|
this.agentConfig.lastStateAuxCodeId = auxCodeId;
|
|
1171
1801
|
this.agentConfig.isAgentLoggedIn = true;
|
|
1172
|
-
|
|
1173
|
-
this.services.webSocketManager.on('message', this.handleWebsocketMessage);
|
|
1802
|
+
await this.ensureWxAppPostStationLogin();
|
|
1174
1803
|
_loggerProxy.default.log(`Silent relogin process completed successfully with login Option: ${reLoginResponse.data.deviceType} teamId: ${reLoginResponse.data.teamId}`, {
|
|
1175
1804
|
module: _constants.CC_FILE,
|
|
1176
1805
|
method: _constants.METHODS.SILENT_RELOGIN,
|
|
@@ -1205,6 +1834,13 @@ class ContactCenter extends _webexCore.WebexPlugin {
|
|
|
1205
1834
|
this.agentConfig.deviceType = deviceType;
|
|
1206
1835
|
switch (deviceType) {
|
|
1207
1836
|
case _types.LoginOption.BROWSER:
|
|
1837
|
+
if (this.isWebRTCRegistrationDisabled()) {
|
|
1838
|
+
_loggerProxy.default.info('Skipping web calling line registration because disableWebRTCRegistration is enabled', {
|
|
1839
|
+
module: _constants.CC_FILE,
|
|
1840
|
+
method: _constants.METHODS.HANDLE_DEVICE_TYPE
|
|
1841
|
+
});
|
|
1842
|
+
break;
|
|
1843
|
+
}
|
|
1208
1844
|
try {
|
|
1209
1845
|
await this.webCallingService.registerWebCallingLine();
|
|
1210
1846
|
} catch (error) {
|
|
@@ -1444,6 +2080,138 @@ class ContactCenter extends _webexCore.WebexPlugin {
|
|
|
1444
2080
|
}
|
|
1445
2081
|
}
|
|
1446
2082
|
|
|
2083
|
+
/**
|
|
2084
|
+
* Skips a campaign preview contact, requesting the next contact from the campaign.
|
|
2085
|
+
*
|
|
2086
|
+
* When a campaign manager reserves a contact for an agent, the agent receives an
|
|
2087
|
+
* `AgentOfferCampaignReservation` event. Instead of accepting, the agent can skip the
|
|
2088
|
+
* preview contact to move to the next contact in the campaign.
|
|
2089
|
+
*
|
|
2090
|
+
* @param {PreviewContactPayload} payload - The preview contact payload containing interactionId and campaignId (campaign name, not UUID).
|
|
2091
|
+
* @returns {Promise<TaskResponse>} Promise resolving with agent contact on success.
|
|
2092
|
+
* @throws {Error} If the operation fails (network error, etc.)
|
|
2093
|
+
*
|
|
2094
|
+
* @example
|
|
2095
|
+
* ```typescript
|
|
2096
|
+
* webex.cc.on('task:campaignPreviewReservation', async (task) => {
|
|
2097
|
+
* const { interactionId } = task.data;
|
|
2098
|
+
* const campaignId = task.data.interaction.callProcessingDetails.campaignId;
|
|
2099
|
+
*
|
|
2100
|
+
* const result = await webex.cc.skipPreviewContact({ interactionId, campaignId });
|
|
2101
|
+
* });
|
|
2102
|
+
* ```
|
|
2103
|
+
*/
|
|
2104
|
+
async skipPreviewContact(payload) {
|
|
2105
|
+
const task = this.taskManager.getTask(payload.interactionId);
|
|
2106
|
+
if (task?.data?.interaction?.callProcessingDetails?.campaignPreviewSkipDisabled === 'true') {
|
|
2107
|
+
_loggerProxy.default.warn('Skip action is disabled for this campaign preview contact', {
|
|
2108
|
+
module: _constants.CC_FILE,
|
|
2109
|
+
method: _constants.METHODS.SKIP_PREVIEW_CONTACT,
|
|
2110
|
+
interactionId: payload.interactionId
|
|
2111
|
+
});
|
|
2112
|
+
throw new Error('Skip action is disabled for this campaign preview contact');
|
|
2113
|
+
}
|
|
2114
|
+
_loggerProxy.default.info('Skipping campaign preview contact', {
|
|
2115
|
+
module: _constants.CC_FILE,
|
|
2116
|
+
method: _constants.METHODS.SKIP_PREVIEW_CONTACT
|
|
2117
|
+
});
|
|
2118
|
+
try {
|
|
2119
|
+
this.metricsManager.timeEvent([_constants4.METRIC_EVENT_NAMES.CAMPAIGN_PREVIEW_SKIP_SUCCESS, _constants4.METRIC_EVENT_NAMES.CAMPAIGN_PREVIEW_SKIP_FAILED]);
|
|
2120
|
+
const result = await this.services.dialer.skipPreviewContact({
|
|
2121
|
+
data: payload
|
|
2122
|
+
});
|
|
2123
|
+
this.metricsManager.trackEvent(_constants4.METRIC_EVENT_NAMES.CAMPAIGN_PREVIEW_SKIP_SUCCESS, {
|
|
2124
|
+
..._MetricsManager.default.getCommonTrackingFieldForAQMResponse(result),
|
|
2125
|
+
interactionId: payload.interactionId,
|
|
2126
|
+
campaignId: payload.campaignId
|
|
2127
|
+
}, ['behavioral', 'business', 'operational']);
|
|
2128
|
+
_loggerProxy.default.log('Campaign preview contact skipped successfully', {
|
|
2129
|
+
module: _constants.CC_FILE,
|
|
2130
|
+
method: _constants.METHODS.SKIP_PREVIEW_CONTACT,
|
|
2131
|
+
trackingId: result.trackingId,
|
|
2132
|
+
interactionId: payload.interactionId
|
|
2133
|
+
});
|
|
2134
|
+
return result;
|
|
2135
|
+
} catch (error) {
|
|
2136
|
+
const failure = error.details;
|
|
2137
|
+
this.metricsManager.trackEvent(_constants4.METRIC_EVENT_NAMES.CAMPAIGN_PREVIEW_SKIP_FAILED, {
|
|
2138
|
+
..._MetricsManager.default.getCommonTrackingFieldForAQMResponseFailed(failure),
|
|
2139
|
+
interactionId: payload.interactionId,
|
|
2140
|
+
campaignId: payload.campaignId
|
|
2141
|
+
}, ['behavioral', 'business', 'operational']);
|
|
2142
|
+
const {
|
|
2143
|
+
error: detailedError
|
|
2144
|
+
} = (0, _Utils.getErrorDetails)(error, _constants.METHODS.SKIP_PREVIEW_CONTACT, _constants.CC_FILE);
|
|
2145
|
+
throw detailedError;
|
|
2146
|
+
}
|
|
2147
|
+
}
|
|
2148
|
+
|
|
2149
|
+
/**
|
|
2150
|
+
* Removes a campaign preview contact from the campaign list entirely.
|
|
2151
|
+
*
|
|
2152
|
+
* When a campaign manager reserves a contact for an agent, the agent receives an
|
|
2153
|
+
* `AgentOfferCampaignReservation` event. Instead of accepting or skipping, the agent can
|
|
2154
|
+
* remove the preview contact to permanently take it out of the campaign contact list.
|
|
2155
|
+
*
|
|
2156
|
+
* @param {PreviewContactPayload} payload - The preview contact payload containing interactionId and campaignId (campaign name, not UUID).
|
|
2157
|
+
* @returns {Promise<TaskResponse>} Promise resolving with agent contact on success.
|
|
2158
|
+
* @throws {Error} If the operation fails (network error, etc.)
|
|
2159
|
+
*
|
|
2160
|
+
* @example
|
|
2161
|
+
* ```typescript
|
|
2162
|
+
* webex.cc.on('task:campaignPreviewReservation', async (task) => {
|
|
2163
|
+
* const { interactionId } = task.data;
|
|
2164
|
+
* const campaignId = task.data.interaction.callProcessingDetails.campaignId;
|
|
2165
|
+
*
|
|
2166
|
+
* const result = await webex.cc.removePreviewContact({ interactionId, campaignId });
|
|
2167
|
+
* });
|
|
2168
|
+
* ```
|
|
2169
|
+
*/
|
|
2170
|
+
async removePreviewContact(payload) {
|
|
2171
|
+
const task = this.taskManager.getTask(payload.interactionId);
|
|
2172
|
+
if (task?.data?.interaction?.callProcessingDetails?.campaignPreviewRemoveDisabled === 'true') {
|
|
2173
|
+
_loggerProxy.default.warn('Remove action is disabled for this campaign preview contact', {
|
|
2174
|
+
module: _constants.CC_FILE,
|
|
2175
|
+
method: _constants.METHODS.REMOVE_PREVIEW_CONTACT,
|
|
2176
|
+
interactionId: payload.interactionId
|
|
2177
|
+
});
|
|
2178
|
+
throw new Error('Remove action is disabled for this campaign preview contact');
|
|
2179
|
+
}
|
|
2180
|
+
_loggerProxy.default.info('Removing campaign preview contact', {
|
|
2181
|
+
module: _constants.CC_FILE,
|
|
2182
|
+
method: _constants.METHODS.REMOVE_PREVIEW_CONTACT
|
|
2183
|
+
});
|
|
2184
|
+
try {
|
|
2185
|
+
this.metricsManager.timeEvent([_constants4.METRIC_EVENT_NAMES.CAMPAIGN_PREVIEW_REMOVE_SUCCESS, _constants4.METRIC_EVENT_NAMES.CAMPAIGN_PREVIEW_REMOVE_FAILED]);
|
|
2186
|
+
const result = await this.services.dialer.removePreviewContact({
|
|
2187
|
+
data: payload
|
|
2188
|
+
});
|
|
2189
|
+
this.metricsManager.trackEvent(_constants4.METRIC_EVENT_NAMES.CAMPAIGN_PREVIEW_REMOVE_SUCCESS, {
|
|
2190
|
+
..._MetricsManager.default.getCommonTrackingFieldForAQMResponse(result),
|
|
2191
|
+
interactionId: payload.interactionId,
|
|
2192
|
+
campaignId: payload.campaignId
|
|
2193
|
+
}, ['behavioral', 'business', 'operational']);
|
|
2194
|
+
_loggerProxy.default.log('Campaign preview contact removed successfully', {
|
|
2195
|
+
module: _constants.CC_FILE,
|
|
2196
|
+
method: _constants.METHODS.REMOVE_PREVIEW_CONTACT,
|
|
2197
|
+
trackingId: result.trackingId,
|
|
2198
|
+
interactionId: payload.interactionId
|
|
2199
|
+
});
|
|
2200
|
+
return result;
|
|
2201
|
+
} catch (error) {
|
|
2202
|
+
const failure = error.details;
|
|
2203
|
+
this.metricsManager.trackEvent(_constants4.METRIC_EVENT_NAMES.CAMPAIGN_PREVIEW_REMOVE_FAILED, {
|
|
2204
|
+
..._MetricsManager.default.getCommonTrackingFieldForAQMResponseFailed(failure),
|
|
2205
|
+
interactionId: payload.interactionId,
|
|
2206
|
+
campaignId: payload.campaignId
|
|
2207
|
+
}, ['behavioral', 'business', 'operational']);
|
|
2208
|
+
const {
|
|
2209
|
+
error: detailedError
|
|
2210
|
+
} = (0, _Utils.getErrorDetails)(error, _constants.METHODS.REMOVE_PREVIEW_CONTACT, _constants.CC_FILE);
|
|
2211
|
+
throw detailedError;
|
|
2212
|
+
}
|
|
2213
|
+
}
|
|
2214
|
+
|
|
1447
2215
|
/**
|
|
1448
2216
|
* Fetches outdial ANI (Automatic Number Identification) entries for an outdial ANI ID.
|
|
1449
2217
|
*
|
|
@@ -1648,8 +2416,8 @@ class ContactCenter extends _webexCore.WebexPlugin {
|
|
|
1648
2416
|
}
|
|
1649
2417
|
|
|
1650
2418
|
/**
|
|
1651
|
-
* Returns paginated entry points
|
|
1652
|
-
*
|
|
2419
|
+
* Returns paginated entry points using the EntryPoint service defaults.
|
|
2420
|
+
* Existing request parameters can override those defaults.
|
|
1653
2421
|
* @public
|
|
1654
2422
|
*/
|
|
1655
2423
|
async getEntryPoints(params = {}) {
|
|
@@ -1657,8 +2425,8 @@ class ContactCenter extends _webexCore.WebexPlugin {
|
|
|
1657
2425
|
}
|
|
1658
2426
|
|
|
1659
2427
|
/**
|
|
1660
|
-
* Returns paginated contact service queues
|
|
1661
|
-
*
|
|
2428
|
+
* Returns paginated contact service queues using the Queue service defaults.
|
|
2429
|
+
* Existing request parameters can override those defaults.
|
|
1662
2430
|
* @public
|
|
1663
2431
|
*/
|
|
1664
2432
|
async getQueues(params = {}) {
|