@webex/contact-center 3.12.0-llmrefactor.1 → 3.12.0-llmrefactor.11
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 +7 -5
- package/ai-docs/ARCHITECTURE.md +1 -1
- package/ai-docs/CONTRACTS.md +8 -3
- package/ai-docs/SECURITY.md +1 -1
- package/ai-docs/contact-center-spec.md +22 -4
- package/ai-docs/features/consult-transfer-list-policy/spec/feature-spec.md +362 -0
- package/dist/cc.js +544 -12
- package/dist/cc.js.map +1 -1
- package/dist/config.js +7 -0
- package/dist/config.js.map +1 -1
- package/dist/constants.js +10 -2
- package/dist/constants.js.map +1 -1
- 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 +104 -0
- package/dist/metrics/behavioral-events.js.map +1 -1
- package/dist/metrics/constants.js +18 -0
- 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/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/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 +3 -0
- package/dist/services/config/Util.js.map +1 -1
- package/dist/services/config/constants.js +10 -6
- package/dist/services/config/constants.js.map +1 -1
- package/dist/services/config/types.js +4 -0
- package/dist/services/config/types.js.map +1 -1
- package/dist/services/core/Err.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/task/Task.js +73 -7
- package/dist/services/task/Task.js.map +1 -1
- package/dist/services/task/TaskFactory.js +8 -4
- package/dist/services/task/TaskFactory.js.map +1 -1
- package/dist/services/task/TaskManager.js +490 -21
- package/dist/services/task/TaskManager.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 +4 -1
- package/dist/services/task/constants.js.map +1 -1
- package/dist/services/task/contact.js +29 -0
- package/dist/services/task/contact.js.map +1 -1
- package/dist/services/task/digital/Digital.js +3 -2
- package/dist/services/task/digital/Digital.js.map +1 -1
- package/dist/services/task/state-machine/TaskStateMachine.js +162 -53
- package/dist/services/task/state-machine/TaskStateMachine.js.map +1 -1
- package/dist/services/task/state-machine/actions.js +6 -1
- package/dist/services/task/state-machine/actions.js.map +1 -1
- package/dist/services/task/state-machine/guards.js +7 -10
- package/dist/services/task/state-machine/guards.js.map +1 -1
- package/dist/services/task/state-machine/types.js.map +1 -1
- package/dist/services/task/state-machine/uiControlsComputer.js +118 -18
- package/dist/services/task/state-machine/uiControlsComputer.js.map +1 -1
- package/dist/services/task/types.js +16 -1
- package/dist/services/task/types.js.map +1 -1
- package/dist/services/task/voice/Voice.js +456 -15
- package/dist/services/task/voice/Voice.js.map +1 -1
- package/dist/services/task/voice/WebRTC.js +4 -1
- package/dist/services/task/voice/WebRTC.js.map +1 -1
- 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 +78 -4
- package/dist/types/config.d.ts +7 -0
- package/dist/types/constants.d.ts +8 -0
- package/dist/types/index.d.ts +3 -1
- package/dist/types/metrics/MetricsManager.d.ts +6 -0
- package/dist/types/metrics/constants.d.ts +17 -0
- package/dist/types/services/AddressBook.d.ts +2 -1
- package/dist/types/services/AnswerCallOnWebexService.d.ts +38 -0
- package/dist/types/services/EntryPoint.d.ts +7 -5
- package/dist/types/services/Queue.d.ts +5 -3
- 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 +8 -5
- package/dist/types/services/config/types.d.ts +17 -4
- package/dist/types/services/core/Err.d.ts +2 -0
- package/dist/types/services/core/WebexRequest.d.ts +1 -0
- package/dist/types/services/core/types.d.ts +2 -0
- package/dist/types/services/task/Task.d.ts +20 -2
- package/dist/types/services/task/TaskFactory.d.ts +2 -1
- package/dist/types/services/task/WebexCallingUtils.d.ts +11 -0
- package/dist/types/services/task/constants.d.ts +3 -0
- package/dist/types/services/task/contact.d.ts +4 -0
- package/dist/types/services/task/digital/Digital.d.ts +2 -2
- package/dist/types/services/task/state-machine/TaskStateMachine.d.ts +304 -56
- package/dist/types/services/task/state-machine/guards.d.ts +6 -5
- package/dist/types/services/task/state-machine/types.d.ts +9 -1
- package/dist/types/services/task/types.d.ts +81 -4
- package/dist/types/services/task/voice/Voice.d.ts +52 -9
- package/dist/types/services/task/voice/WebRTC.d.ts +2 -2
- 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 +14 -8
- package/dist/types/utils/PageCache.d.ts +20 -3
- package/dist/types.js +7 -2
- 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 +1 -1
- package/package.json +8 -8
- package/src/cc.ts +657 -12
- package/src/config.ts +7 -0
- package/src/constants.ts +8 -0
- package/src/index.ts +2 -0
- package/src/metrics/MetricsManager.ts +16 -0
- package/src/metrics/ai-docs/metrics-spec.md +78 -10
- package/src/metrics/behavioral-events.ts +106 -0
- package/src/metrics/constants.ts +20 -0
- package/src/services/AddressBook.ts +17 -6
- package/src/services/AnswerCallOnWebexService.ts +239 -0
- package/src/services/EntryPoint.ts +59 -60
- package/src/services/Queue.ts +29 -12
- package/src/services/WebexCrossClientService.ts +293 -0
- package/src/services/WxAppTelephonyMercurySync.ts +142 -0
- package/src/services/agent/ai-docs/agent-spec.md +1 -0
- package/src/services/ai-docs/AGENTS.md +10 -10
- package/src/services/ai-docs/services-spec.md +6 -1
- package/src/services/config/Util.ts +3 -0
- package/src/services/config/ai-docs/AGENTS.md +1 -1
- package/src/services/config/ai-docs/ARCHITECTURE.md +2 -2
- package/src/services/config/ai-docs/config-spec.md +6 -0
- package/src/services/config/constants.ts +10 -6
- package/src/services/config/types.ts +16 -4
- package/src/services/core/Err.ts +1 -0
- package/src/services/core/WebexRequest.ts +3 -1
- package/src/services/core/ai-docs/core-spec.md +5 -1
- package/src/services/core/aqm-reqs.ts +30 -15
- package/src/services/core/types.ts +2 -0
- package/src/services/task/Task.ts +79 -8
- package/src/services/task/TaskFactory.ts +8 -3
- package/src/services/task/TaskManager.ts +716 -17
- package/src/services/task/WebexCallingUtils.ts +136 -0
- package/src/services/task/ai-docs/ARCHITECTURE.md +1 -0
- package/src/services/task/ai-docs/task-spec.md +156 -3
- package/src/services/task/constants.ts +3 -0
- package/src/services/task/contact.ts +30 -0
- package/src/services/task/digital/Digital.ts +4 -2
- package/src/services/task/state-machine/TaskStateMachine.ts +235 -81
- package/src/services/task/state-machine/actions.ts +5 -2
- package/src/services/task/state-machine/ai-docs/AGENTS.md +6 -4
- package/src/services/task/state-machine/ai-docs/ARCHITECTURE.md +35 -16
- package/src/services/task/state-machine/ai-docs/task-state-machine-spec.md +103 -33
- package/src/services/task/state-machine/guards.ts +7 -10
- package/src/services/task/state-machine/types.ts +16 -1
- package/src/services/task/state-machine/uiControlsComputer.ts +206 -32
- package/src/services/task/types.ts +114 -4
- package/src/services/task/voice/Voice.ts +595 -14
- package/src/services/task/voice/WebRTC.ts +5 -1
- 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 +33 -9
- package/src/utils/AGENTS.md +21 -10
- package/src/utils/PageCache.ts +38 -5
- package/src/utils/ai-docs/utils-spec.md +21 -11
- package/test/unit/spec/cc.ts +1522 -19
- 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/EntryPoint.ts +87 -40
- package/test/unit/spec/services/Queue.ts +123 -12
- 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/core/WebexRequest.ts +3 -1
- package/test/unit/spec/services/core/aqm-reqs.ts +113 -1
- package/test/unit/spec/services/task/Task.ts +274 -6
- package/test/unit/spec/services/task/TaskFactory.ts +39 -2
- package/test/unit/spec/services/task/TaskManager.ts +1717 -9
- 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/state-machine/TaskStateMachine.ts +1485 -109
- package/test/unit/spec/services/task/state-machine/guards.ts +210 -8
- package/test/unit/spec/services/task/state-machine/uiControlsComputer.ts +445 -7
- package/test/unit/spec/services/task/voice/Voice.ts +1412 -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/src/cc.ts
CHANGED
|
@@ -56,6 +56,10 @@ import {
|
|
|
56
56
|
import {ConnectionLostDetails} from './services/core/websocket/types';
|
|
57
57
|
import TaskManager from './services/task/TaskManager';
|
|
58
58
|
import WebCallingService from './services/WebCallingService';
|
|
59
|
+
import AnswerCallOnWebexService from './services/AnswerCallOnWebexService';
|
|
60
|
+
import WebexCrossClientService from './services/WebexCrossClientService';
|
|
61
|
+
import WxAppTelephonyMercurySync from './services/WxAppTelephonyMercurySync';
|
|
62
|
+
import {logWxAppSessionReadiness} from './services/wxAppDiagnosticLogging';
|
|
59
63
|
import {
|
|
60
64
|
ITask,
|
|
61
65
|
TASK_EVENTS,
|
|
@@ -232,6 +236,34 @@ export default class ContactCenter extends WebexPlugin implements IContactCenter
|
|
|
232
236
|
*/
|
|
233
237
|
private webCallingService: WebCallingService;
|
|
234
238
|
|
|
239
|
+
/**
|
|
240
|
+
* REST telephony for wxApp thick-client answer (WXCC-6026)
|
|
241
|
+
* @private
|
|
242
|
+
*/
|
|
243
|
+
private answerCallOnWebexService: AnswerCallOnWebexService;
|
|
244
|
+
|
|
245
|
+
/**
|
|
246
|
+
* usersub cross-client state for Webex App toast suppression
|
|
247
|
+
* @private
|
|
248
|
+
*/
|
|
249
|
+
private webexCrossClientService: WebexCrossClientService;
|
|
250
|
+
|
|
251
|
+
/**
|
|
252
|
+
* Mercury telephony mute sync for wxApp thick-client answer
|
|
253
|
+
* @private
|
|
254
|
+
*/
|
|
255
|
+
private wxAppTelephonyMercurySync: WxAppTelephonyMercurySync;
|
|
256
|
+
|
|
257
|
+
/** True when wxApp mute sync opened Mercury (Extension/DN-only profiles). */
|
|
258
|
+
private wxAppMercuryConnectedByCc = false;
|
|
259
|
+
|
|
260
|
+
/** True when wxApp mute sync registered the Webex device. */
|
|
261
|
+
private wxAppDeviceRegisteredByCc = false;
|
|
262
|
+
|
|
263
|
+
private static readonly WXAPP_FALSE_PUBLISH_RETRY_DELAY_MS = 30_000;
|
|
264
|
+
private static readonly WXAPP_FALSE_PUBLISH_MAX_RETRIES = 3;
|
|
265
|
+
private wxAppFalsePublishRetryTimer?: ReturnType<typeof setTimeout>;
|
|
266
|
+
|
|
235
267
|
/**
|
|
236
268
|
* Core service managers for Contact Center operations
|
|
237
269
|
* Includes agent, connection, and configuration services
|
|
@@ -405,6 +437,9 @@ export default class ContactCenter extends WebexPlugin implements IContactCenter
|
|
|
405
437
|
});
|
|
406
438
|
|
|
407
439
|
this.webCallingService = new WebCallingService(this.$webex);
|
|
440
|
+
this.answerCallOnWebexService = new AnswerCallOnWebexService(this.$webex);
|
|
441
|
+
this.webexCrossClientService = new WebexCrossClientService(this.$webex);
|
|
442
|
+
this.wxAppTelephonyMercurySync = new WxAppTelephonyMercurySync(this.$webex);
|
|
408
443
|
this.apiAIAssistant = new ApiAIAssistant(this.$webex);
|
|
409
444
|
this.metricsManager = MetricsManager.getInstance({webex: this.$webex});
|
|
410
445
|
this.taskManager = TaskManager.getTaskManager(
|
|
@@ -414,6 +449,7 @@ export default class ContactCenter extends WebexPlugin implements IContactCenter
|
|
|
414
449
|
this.services.webSocketManager,
|
|
415
450
|
this.services.rtdWebSocketManager
|
|
416
451
|
);
|
|
452
|
+
this.taskManager.setAnswerCallOnWebexService(this.answerCallOnWebexService);
|
|
417
453
|
this.incomingTaskListener();
|
|
418
454
|
|
|
419
455
|
// Initialize API instances
|
|
@@ -634,6 +670,10 @@ export default class ContactCenter extends WebexPlugin implements IContactCenter
|
|
|
634
670
|
this.services.rtdWebSocketManager.off('message', this.handleRTDWebsocketMessage);
|
|
635
671
|
this.services.connectionService.off('connectionLost', this.handleConnectionLost);
|
|
636
672
|
|
|
673
|
+
const {publishError: wxAppPublishError} = await this.teardownWxAppLocalState({
|
|
674
|
+
clearInitFlag: true,
|
|
675
|
+
});
|
|
676
|
+
|
|
637
677
|
if (
|
|
638
678
|
this.agentConfig.webRtcEnabled &&
|
|
639
679
|
this.agentConfig.loginVoiceOptions.includes(LoginOption.BROWSER)
|
|
@@ -665,6 +705,10 @@ export default class ContactCenter extends WebexPlugin implements IContactCenter
|
|
|
665
705
|
// Clear any cached agent configuration
|
|
666
706
|
this.agentConfig = null;
|
|
667
707
|
|
|
708
|
+
if (wxAppPublishError) {
|
|
709
|
+
throw wxAppPublishError;
|
|
710
|
+
}
|
|
711
|
+
|
|
668
712
|
LoggerProxy.log('Deregistered successfully', {
|
|
669
713
|
module: CC_FILE,
|
|
670
714
|
method: METHODS.DEREGISTER,
|
|
@@ -727,6 +771,9 @@ export default class ContactCenter extends WebexPlugin implements IContactCenter
|
|
|
727
771
|
* ```
|
|
728
772
|
*/
|
|
729
773
|
public async getBuddyAgents(data: BuddyAgents): Promise<BuddyAgentsResponse> {
|
|
774
|
+
const {action, state, mediaType = 'telephony'} = data;
|
|
775
|
+
const buddyAgentState = state ?? (action === 'Transfer' ? AGENT_STATE_AVAILABLE : undefined);
|
|
776
|
+
|
|
730
777
|
LoggerProxy.info('Fetching buddy agents', {
|
|
731
778
|
module: CC_FILE,
|
|
732
779
|
method: METHODS.GET_BUDDY_AGENTS,
|
|
@@ -737,15 +784,19 @@ export default class ContactCenter extends WebexPlugin implements IContactCenter
|
|
|
737
784
|
METRIC_EVENT_NAMES.FETCH_BUDDY_AGENTS_FAILED,
|
|
738
785
|
]);
|
|
739
786
|
const resp = await this.services.agent.buddyAgents({
|
|
740
|
-
data: {
|
|
787
|
+
data: {
|
|
788
|
+
agentProfileId: this.agentConfig.agentProfileID,
|
|
789
|
+
mediaType,
|
|
790
|
+
...(buddyAgentState ? {state: buddyAgentState} : {}),
|
|
791
|
+
},
|
|
741
792
|
});
|
|
742
793
|
|
|
743
794
|
this.metricsManager.trackEvent(
|
|
744
795
|
METRIC_EVENT_NAMES.FETCH_BUDDY_AGENTS_SUCCESS,
|
|
745
796
|
{
|
|
746
797
|
...MetricsManager.getCommonTrackingFieldForAQMResponse(resp),
|
|
747
|
-
mediaType
|
|
748
|
-
buddyAgentState
|
|
798
|
+
mediaType,
|
|
799
|
+
buddyAgentState,
|
|
749
800
|
buddyAgentCount: resp.data.agentList.length,
|
|
750
801
|
},
|
|
751
802
|
['operational']
|
|
@@ -765,8 +816,8 @@ export default class ContactCenter extends WebexPlugin implements IContactCenter
|
|
|
765
816
|
METRIC_EVENT_NAMES.FETCH_BUDDY_AGENTS_FAILED,
|
|
766
817
|
{
|
|
767
818
|
...MetricsManager.getCommonTrackingFieldForAQMResponseFailed(failureResp),
|
|
768
|
-
mediaType
|
|
769
|
-
buddyAgentState
|
|
819
|
+
mediaType,
|
|
820
|
+
buddyAgentState,
|
|
770
821
|
},
|
|
771
822
|
['operational']
|
|
772
823
|
);
|
|
@@ -808,6 +859,13 @@ export default class ContactCenter extends WebexPlugin implements IContactCenter
|
|
|
808
859
|
webRtcEnabled: this.agentConfig.webRtcEnabled,
|
|
809
860
|
autoWrapup: this.agentConfig.wrapUpData?.wrapUpProps?.autoWrapup ?? false,
|
|
810
861
|
aiFeature: this.agentConfig.aiFeature,
|
|
862
|
+
consultTransfer: {
|
|
863
|
+
allowConsultToQueue: this.agentConfig.allowConsultToQueue,
|
|
864
|
+
accessQueue: this.agentConfig.accessQueue,
|
|
865
|
+
accessEntryPoint: this.agentConfig.accessEntryPoint,
|
|
866
|
+
accessBuddyTeam: this.agentConfig.accessBuddyTeam,
|
|
867
|
+
},
|
|
868
|
+
enableWxBetterTogether: this.isWxBetterTogetherEnabled(),
|
|
811
869
|
};
|
|
812
870
|
this.taskManager.setConfigFlags(configFlags);
|
|
813
871
|
// TODO: Make profile a singleton to make it available throughout app/sdk so we dont need to inject info everywhere
|
|
@@ -958,14 +1016,15 @@ export default class ContactCenter extends WebexPlugin implements IContactCenter
|
|
|
958
1016
|
}
|
|
959
1017
|
}
|
|
960
1018
|
|
|
1019
|
+
const deviceId = this.getDeviceId(data.loginOption, data.dialNumber);
|
|
961
1020
|
const loginResponse = await this.services.agent.stationLogin({
|
|
962
1021
|
data: {
|
|
963
|
-
|
|
964
|
-
|
|
1022
|
+
// BROWSER DN must be webrtc-{agentId} so VPOP/RTMS do not treat a bare UUID as PSTN.
|
|
1023
|
+
dialNumber: data.loginOption === LoginOption.BROWSER ? deviceId : data.dialNumber,
|
|
965
1024
|
teamId: data.teamId,
|
|
966
1025
|
deviceType: data.loginOption,
|
|
967
1026
|
isExtension: data.loginOption === LoginOption.EXTENSION,
|
|
968
|
-
deviceId
|
|
1027
|
+
deviceId,
|
|
969
1028
|
roles: [AGENT],
|
|
970
1029
|
teamName: EMPTY_STRING,
|
|
971
1030
|
siteId: EMPTY_STRING,
|
|
@@ -1009,6 +1068,16 @@ export default class ContactCenter extends WebexPlugin implements IContactCenter
|
|
|
1009
1068
|
};
|
|
1010
1069
|
|
|
1011
1070
|
this.webCallingService.setLoginOption(data.loginOption);
|
|
1071
|
+
if (this.agentConfig) {
|
|
1072
|
+
this.agentConfig.deviceType = data.loginOption;
|
|
1073
|
+
if (
|
|
1074
|
+
data.loginOption === LoginOption.AGENT_DN ||
|
|
1075
|
+
data.loginOption === LoginOption.EXTENSION
|
|
1076
|
+
) {
|
|
1077
|
+
this.agentConfig.defaultDn = data.dialNumber;
|
|
1078
|
+
this.agentConfig.dn = data.dialNumber;
|
|
1079
|
+
}
|
|
1080
|
+
}
|
|
1012
1081
|
this.metricsManager.trackEvent(
|
|
1013
1082
|
METRIC_EVENT_NAMES.STATION_LOGIN_SUCCESS,
|
|
1014
1083
|
{
|
|
@@ -1030,6 +1099,8 @@ export default class ContactCenter extends WebexPlugin implements IContactCenter
|
|
|
1030
1099
|
}
|
|
1031
1100
|
);
|
|
1032
1101
|
|
|
1102
|
+
await this.ensureWxAppPostStationLogin();
|
|
1103
|
+
|
|
1033
1104
|
return response;
|
|
1034
1105
|
} catch (error) {
|
|
1035
1106
|
const failure = error.details as Failure;
|
|
@@ -1098,6 +1169,8 @@ export default class ContactCenter extends WebexPlugin implements IContactCenter
|
|
|
1098
1169
|
this.webCallingService.deregisterWebCallingLine();
|
|
1099
1170
|
}
|
|
1100
1171
|
|
|
1172
|
+
await this.teardownWxAppLocalState();
|
|
1173
|
+
|
|
1101
1174
|
LoggerProxy.log(`Agent station logout completed successfully`, {
|
|
1102
1175
|
module: CC_FILE,
|
|
1103
1176
|
method: METHODS.STATION_LOGOUT,
|
|
@@ -1377,6 +1450,576 @@ export default class ContactCenter extends WebexPlugin implements IContactCenter
|
|
|
1377
1450
|
}
|
|
1378
1451
|
}
|
|
1379
1452
|
|
|
1453
|
+
/**
|
|
1454
|
+
* Whether wxApp thick-client answer is enabled for this SDK instance.
|
|
1455
|
+
* @public
|
|
1456
|
+
*/
|
|
1457
|
+
public isWxBetterTogetherEnabled(): boolean {
|
|
1458
|
+
return this.$config?.enableWxBetterTogether === true;
|
|
1459
|
+
}
|
|
1460
|
+
|
|
1461
|
+
/**
|
|
1462
|
+
* Current station login option (Extension, Dial Number, or Browser/Desktop).
|
|
1463
|
+
* Prefer webCallingService — updated on every stationLogin before wxApp hooks run.
|
|
1464
|
+
* @private
|
|
1465
|
+
*/
|
|
1466
|
+
private getCurrentStationLoginOption(): LoginOption | undefined {
|
|
1467
|
+
return this.webCallingService?.loginOption ?? this.agentConfig?.deviceType;
|
|
1468
|
+
}
|
|
1469
|
+
|
|
1470
|
+
/**
|
|
1471
|
+
* wxApp thick-client answer is supported for Extension and Dial Number station login only —
|
|
1472
|
+
* not Browser/Desktop (WebRTC) login.
|
|
1473
|
+
* @private
|
|
1474
|
+
*/
|
|
1475
|
+
private assertWxAppStationLoginSupportedForEnable(): void {
|
|
1476
|
+
const loginOption = this.getCurrentStationLoginOption();
|
|
1477
|
+
if (loginOption !== LoginOption.EXTENSION && loginOption !== LoginOption.AGENT_DN) {
|
|
1478
|
+
throw new Error(
|
|
1479
|
+
'setManageWebexCallingInWxcc requires EXTENSION or AGENT_DN station login. Complete station login before enabling.'
|
|
1480
|
+
);
|
|
1481
|
+
}
|
|
1482
|
+
}
|
|
1483
|
+
|
|
1484
|
+
/**
|
|
1485
|
+
* Clears runtime wxApp config after logout/deregister so stale flags do not apply on relogin.
|
|
1486
|
+
* @private
|
|
1487
|
+
*/
|
|
1488
|
+
private resetEnableWxBetterTogetherConfig(): void {
|
|
1489
|
+
if (this.$config) {
|
|
1490
|
+
this.$config.enableWxBetterTogether = false;
|
|
1491
|
+
}
|
|
1492
|
+
this.taskManager.applyEnableWxBetterTogether(false);
|
|
1493
|
+
}
|
|
1494
|
+
|
|
1495
|
+
/**
|
|
1496
|
+
* Runtime enable/disable for wxApp Better Together (toast suppression + Mercury mute sync).
|
|
1497
|
+
*
|
|
1498
|
+
* **Phase 1 (WXCC-6026 / MMT): NOT part of the public host contract.**
|
|
1499
|
+
* Hosts must set `webexConfig.cc.enableWxBetterTogether` before `webex.init()` / `cc.register()`.
|
|
1500
|
+
* To change the flag after the SDK is initialized, re-init the SDK with the updated config.
|
|
1501
|
+
*
|
|
1502
|
+
* **Supported public read API:** {@link isWxBetterTogetherEnabled}.
|
|
1503
|
+
* **Supported telephony API:** unified `task.accept()`, `task.decline()`, `task.toggleMute()`,
|
|
1504
|
+
* `task.transmitDtmf()` — SDK routes wxApp calls internally when the init flag is active.
|
|
1505
|
+
*
|
|
1506
|
+
* **Production lifecycle does not call this method.** Station login, silent relogin, logout,
|
|
1507
|
+
* and deregister use {@link ensureWxAppPostStationLogin} and {@link teardownWxAppLocalState}
|
|
1508
|
+
* (usersub publish + Mercury subscribe/unsubscribe based on the init flag).
|
|
1509
|
+
*
|
|
1510
|
+
* This setter remains as a **private implementation** for Phase 2 runtime toggle and unit tests.
|
|
1511
|
+
* It updates `$config.enableWxBetterTogether`, TaskManager flags, cross-client usersub
|
|
1512
|
+
* (`answer-calls-on-wxcc`), and Mercury mute sync; rolls back config on publish/connect failure.
|
|
1513
|
+
*
|
|
1514
|
+
* @param enabled - `true` to enable wxApp answer + usersub suppression; `false` to disable and tear down.
|
|
1515
|
+
* @throws When enabling without login, on unsupported BROWSER station login, or when usersub/Mercury init fails.
|
|
1516
|
+
* @internal
|
|
1517
|
+
* @see enableWxBetterTogether (CCPluginConfig init flag)
|
|
1518
|
+
* @see ensureWxAppPostStationLogin
|
|
1519
|
+
* @see teardownWxAppLocalState
|
|
1520
|
+
*/
|
|
1521
|
+
private async setManageWebexCallingInWxcc(enabled: boolean): Promise<void> {
|
|
1522
|
+
if (enabled && !this.$webex.internal.device?.userId) {
|
|
1523
|
+
throw new Error('Cannot publish answer-calls-on-wxcc: user is not logged in');
|
|
1524
|
+
}
|
|
1525
|
+
|
|
1526
|
+
if (enabled) {
|
|
1527
|
+
this.assertWxAppStationLoginSupportedForEnable();
|
|
1528
|
+
}
|
|
1529
|
+
|
|
1530
|
+
const previousEnabled = this.isWxBetterTogetherEnabled();
|
|
1531
|
+
|
|
1532
|
+
if (this.$config) {
|
|
1533
|
+
this.$config.enableWxBetterTogether = enabled;
|
|
1534
|
+
}
|
|
1535
|
+
|
|
1536
|
+
this.taskManager.applyEnableWxBetterTogether(enabled);
|
|
1537
|
+
|
|
1538
|
+
let publishedEnable = false;
|
|
1539
|
+
|
|
1540
|
+
try {
|
|
1541
|
+
if (enabled) {
|
|
1542
|
+
await this.ensureWxAppMercuryAndSubscribe();
|
|
1543
|
+
await this.publishAnswerOnWebexCrossClientState(true);
|
|
1544
|
+
publishedEnable = true;
|
|
1545
|
+
this.taskManager.syncWxAppMuteFromCallDetailsForAllTasks();
|
|
1546
|
+
} else {
|
|
1547
|
+
await this.publishAnswerOnWebexCrossClientState(false);
|
|
1548
|
+
this.wxAppTelephonyMercurySync.unsubscribe();
|
|
1549
|
+
await this.releaseWxAppMercuryResources();
|
|
1550
|
+
}
|
|
1551
|
+
} catch (error) {
|
|
1552
|
+
if (publishedEnable) {
|
|
1553
|
+
await this.revertWxAppCrossClientPublish();
|
|
1554
|
+
} else if (enabled) {
|
|
1555
|
+
this.wxAppTelephonyMercurySync.unsubscribe();
|
|
1556
|
+
await this.releaseWxAppMercuryResources();
|
|
1557
|
+
}
|
|
1558
|
+
|
|
1559
|
+
if (this.$config) {
|
|
1560
|
+
this.$config.enableWxBetterTogether = previousEnabled;
|
|
1561
|
+
}
|
|
1562
|
+
this.taskManager.applyEnableWxBetterTogether(previousEnabled);
|
|
1563
|
+
throw error;
|
|
1564
|
+
}
|
|
1565
|
+
}
|
|
1566
|
+
|
|
1567
|
+
private getWxAppTelephonyTaskType(): 'Voice' | 'WebRTC' | 'unknown' {
|
|
1568
|
+
const loginOption = this.getCurrentStationLoginOption();
|
|
1569
|
+
|
|
1570
|
+
if (loginOption === LoginOption.BROWSER) {
|
|
1571
|
+
return 'WebRTC';
|
|
1572
|
+
}
|
|
1573
|
+
|
|
1574
|
+
if (loginOption === LoginOption.EXTENSION || loginOption === LoginOption.AGENT_DN) {
|
|
1575
|
+
return 'Voice';
|
|
1576
|
+
}
|
|
1577
|
+
|
|
1578
|
+
return 'unknown';
|
|
1579
|
+
}
|
|
1580
|
+
|
|
1581
|
+
private async ensureWxAppPostStationLogin(): Promise<void> {
|
|
1582
|
+
const loginOption = this.getCurrentStationLoginOption();
|
|
1583
|
+
const flagEnabled = this.isWxBetterTogetherEnabled();
|
|
1584
|
+
const telephonyTaskType = this.getWxAppTelephonyTaskType();
|
|
1585
|
+
|
|
1586
|
+
if (loginOption === LoginOption.BROWSER) {
|
|
1587
|
+
if (flagEnabled) {
|
|
1588
|
+
logWxAppSessionReadiness({
|
|
1589
|
+
enableWxBetterTogether: true,
|
|
1590
|
+
loginOption,
|
|
1591
|
+
wxAppHooksApplied: false,
|
|
1592
|
+
usersubPublished: false,
|
|
1593
|
+
mercurySubscribed: false,
|
|
1594
|
+
telephonyTaskType,
|
|
1595
|
+
skipReason: 'unsupported_browser_login',
|
|
1596
|
+
});
|
|
1597
|
+
|
|
1598
|
+
this.metricsManager.trackEvent(
|
|
1599
|
+
METRIC_EVENT_NAMES.WXAPP_SESSION_SKIPPED,
|
|
1600
|
+
{
|
|
1601
|
+
loginOption,
|
|
1602
|
+
enableWxBetterTogether: true,
|
|
1603
|
+
skipReason: 'unsupported_browser_login',
|
|
1604
|
+
},
|
|
1605
|
+
['operational', 'behavioral']
|
|
1606
|
+
);
|
|
1607
|
+
}
|
|
1608
|
+
|
|
1609
|
+
return;
|
|
1610
|
+
}
|
|
1611
|
+
|
|
1612
|
+
let publishedEnable = false;
|
|
1613
|
+
let wxAppInitStage: 'mercury' | 'publish' = 'mercury';
|
|
1614
|
+
|
|
1615
|
+
try {
|
|
1616
|
+
if (flagEnabled) {
|
|
1617
|
+
this.metricsManager.timeEvent([
|
|
1618
|
+
METRIC_EVENT_NAMES.WXAPP_SESSION_INIT_SUCCESS,
|
|
1619
|
+
METRIC_EVENT_NAMES.WXAPP_SESSION_INIT_FAILED,
|
|
1620
|
+
]);
|
|
1621
|
+
|
|
1622
|
+
await this.ensureWxAppMercuryAndSubscribe();
|
|
1623
|
+
wxAppInitStage = 'publish';
|
|
1624
|
+
await this.publishAnswerOnWebexCrossClientState(true);
|
|
1625
|
+
publishedEnable = true;
|
|
1626
|
+
this.taskManager.syncWxAppMuteFromCallDetailsForAllTasks();
|
|
1627
|
+
|
|
1628
|
+
const mercurySubscribed = this.wxAppTelephonyMercurySync.isSubscribed();
|
|
1629
|
+
const usersubPublished = this.webexCrossClientService.isAnswerCallsStateActive();
|
|
1630
|
+
|
|
1631
|
+
logWxAppSessionReadiness({
|
|
1632
|
+
enableWxBetterTogether: true,
|
|
1633
|
+
loginOption,
|
|
1634
|
+
wxAppHooksApplied: true,
|
|
1635
|
+
usersubPublished,
|
|
1636
|
+
mercurySubscribed,
|
|
1637
|
+
telephonyTaskType,
|
|
1638
|
+
});
|
|
1639
|
+
|
|
1640
|
+
const sessionInitReady = mercurySubscribed && usersubPublished;
|
|
1641
|
+
|
|
1642
|
+
if (sessionInitReady) {
|
|
1643
|
+
this.metricsManager.trackEvent(
|
|
1644
|
+
METRIC_EVENT_NAMES.WXAPP_SESSION_INIT_SUCCESS,
|
|
1645
|
+
{loginOption, enableWxBetterTogether: true},
|
|
1646
|
+
['operational', 'behavioral']
|
|
1647
|
+
);
|
|
1648
|
+
} else {
|
|
1649
|
+
this.metricsManager.trackEvent(
|
|
1650
|
+
METRIC_EVENT_NAMES.WXAPP_SESSION_INIT_FAILED,
|
|
1651
|
+
{
|
|
1652
|
+
loginOption,
|
|
1653
|
+
enableWxBetterTogether: true,
|
|
1654
|
+
skipReason: !usersubPublished ? 'usersub_not_published' : 'mercury_not_subscribed',
|
|
1655
|
+
},
|
|
1656
|
+
['operational', 'behavioral']
|
|
1657
|
+
);
|
|
1658
|
+
}
|
|
1659
|
+
} else {
|
|
1660
|
+
await this.ensureWxAppDeviceRegistered();
|
|
1661
|
+
await this.publishAnswerOnWebexCrossClientState(false, {force: true});
|
|
1662
|
+
this.webexCrossClientService.teardown();
|
|
1663
|
+
this.wxAppTelephonyMercurySync.unsubscribe();
|
|
1664
|
+
await this.releaseWxAppMercuryResources();
|
|
1665
|
+
|
|
1666
|
+
logWxAppSessionReadiness({
|
|
1667
|
+
enableWxBetterTogether: false,
|
|
1668
|
+
loginOption,
|
|
1669
|
+
wxAppHooksApplied: true,
|
|
1670
|
+
usersubPublished: false,
|
|
1671
|
+
mercurySubscribed: false,
|
|
1672
|
+
telephonyTaskType,
|
|
1673
|
+
skipReason: 'flag_disabled',
|
|
1674
|
+
});
|
|
1675
|
+
|
|
1676
|
+
this.metricsManager.trackEvent(
|
|
1677
|
+
METRIC_EVENT_NAMES.WXAPP_SESSION_SKIPPED,
|
|
1678
|
+
{loginOption, enableWxBetterTogether: false, skipReason: 'flag_disabled'},
|
|
1679
|
+
['operational', 'behavioral']
|
|
1680
|
+
);
|
|
1681
|
+
}
|
|
1682
|
+
} catch (error) {
|
|
1683
|
+
LoggerProxy.error(`Failed to initialize wxApp post-station-login: ${error}`, {
|
|
1684
|
+
module: CC_FILE,
|
|
1685
|
+
method: METHODS.STATION_LOGIN,
|
|
1686
|
+
});
|
|
1687
|
+
|
|
1688
|
+
if (flagEnabled) {
|
|
1689
|
+
const sessionInitFailureReason =
|
|
1690
|
+
wxAppInitStage === 'mercury' ? 'mercury_subscribe_failed' : 'publish_failed';
|
|
1691
|
+
|
|
1692
|
+
this.metricsManager.trackEvent(
|
|
1693
|
+
METRIC_EVENT_NAMES.WXAPP_SESSION_INIT_FAILED,
|
|
1694
|
+
{
|
|
1695
|
+
loginOption,
|
|
1696
|
+
enableWxBetterTogether: true,
|
|
1697
|
+
skipReason: sessionInitFailureReason,
|
|
1698
|
+
error: error instanceof Error ? error.toString() : String(error),
|
|
1699
|
+
},
|
|
1700
|
+
['operational', 'behavioral']
|
|
1701
|
+
);
|
|
1702
|
+
|
|
1703
|
+
logWxAppSessionReadiness({
|
|
1704
|
+
enableWxBetterTogether: true,
|
|
1705
|
+
loginOption,
|
|
1706
|
+
wxAppHooksApplied: false,
|
|
1707
|
+
usersubPublished:
|
|
1708
|
+
publishedEnable && this.webexCrossClientService.isAnswerCallsStateActive(),
|
|
1709
|
+
mercurySubscribed: this.wxAppTelephonyMercurySync.isSubscribed(),
|
|
1710
|
+
telephonyTaskType,
|
|
1711
|
+
skipReason: sessionInitFailureReason,
|
|
1712
|
+
});
|
|
1713
|
+
|
|
1714
|
+
if (publishedEnable) {
|
|
1715
|
+
await this.revertWxAppCrossClientPublish();
|
|
1716
|
+
} else {
|
|
1717
|
+
this.wxAppTelephonyMercurySync.unsubscribe();
|
|
1718
|
+
await this.releaseWxAppMercuryResources();
|
|
1719
|
+
}
|
|
1720
|
+
this.resetEnableWxBetterTogetherConfig();
|
|
1721
|
+
} else {
|
|
1722
|
+
this.scheduleForcedFalsePublishRetry();
|
|
1723
|
+
}
|
|
1724
|
+
}
|
|
1725
|
+
}
|
|
1726
|
+
|
|
1727
|
+
private clearWxAppFalsePublishRetryTimer(): void {
|
|
1728
|
+
if (this.wxAppFalsePublishRetryTimer) {
|
|
1729
|
+
clearTimeout(this.wxAppFalsePublishRetryTimer);
|
|
1730
|
+
this.wxAppFalsePublishRetryTimer = undefined;
|
|
1731
|
+
}
|
|
1732
|
+
}
|
|
1733
|
+
|
|
1734
|
+
private scheduleForcedFalsePublishRetry(retryAttempt = 0): void {
|
|
1735
|
+
this.scheduleFalsePublishRetry(retryAttempt, {requireDisabled: true});
|
|
1736
|
+
}
|
|
1737
|
+
|
|
1738
|
+
/**
|
|
1739
|
+
* Retries compensating false publish after rollback failure, regardless of enabled flag.
|
|
1740
|
+
* @private
|
|
1741
|
+
*/
|
|
1742
|
+
private scheduleCompensatingFalsePublishRetry(retryAttempt = 0): void {
|
|
1743
|
+
this.scheduleFalsePublishRetry(retryAttempt);
|
|
1744
|
+
}
|
|
1745
|
+
|
|
1746
|
+
private scheduleFalsePublishRetry(
|
|
1747
|
+
retryAttempt = 0,
|
|
1748
|
+
options: {requireDisabled?: boolean} = {}
|
|
1749
|
+
): void {
|
|
1750
|
+
if (retryAttempt >= ContactCenter.WXAPP_FALSE_PUBLISH_MAX_RETRIES) {
|
|
1751
|
+
return;
|
|
1752
|
+
}
|
|
1753
|
+
|
|
1754
|
+
if (options?.requireDisabled && this.isWxBetterTogetherEnabled()) {
|
|
1755
|
+
return;
|
|
1756
|
+
}
|
|
1757
|
+
|
|
1758
|
+
this.clearWxAppFalsePublishRetryTimer();
|
|
1759
|
+
|
|
1760
|
+
this.wxAppFalsePublishRetryTimer = setTimeout(async () => {
|
|
1761
|
+
this.wxAppFalsePublishRetryTimer = undefined;
|
|
1762
|
+
|
|
1763
|
+
if (options?.requireDisabled && this.isWxBetterTogetherEnabled()) {
|
|
1764
|
+
return;
|
|
1765
|
+
}
|
|
1766
|
+
|
|
1767
|
+
if (
|
|
1768
|
+
!options?.requireDisabled &&
|
|
1769
|
+
this.isWxBetterTogetherEnabled() &&
|
|
1770
|
+
this.webexCrossClientService.isAnswerCallsStateActive()
|
|
1771
|
+
) {
|
|
1772
|
+
return;
|
|
1773
|
+
}
|
|
1774
|
+
|
|
1775
|
+
try {
|
|
1776
|
+
await this.ensureWxAppDeviceRegistered();
|
|
1777
|
+
await this.publishAnswerOnWebexCrossClientState(false, {force: true});
|
|
1778
|
+
this.webexCrossClientService.teardown();
|
|
1779
|
+
this.wxAppTelephonyMercurySync.unsubscribe();
|
|
1780
|
+
await this.releaseWxAppMercuryResources();
|
|
1781
|
+
} catch (retryError) {
|
|
1782
|
+
LoggerProxy.error(
|
|
1783
|
+
`Failed to retry forced answer-calls-on-wxcc false publish: ${retryError}`,
|
|
1784
|
+
{
|
|
1785
|
+
module: CC_FILE,
|
|
1786
|
+
method: METHODS.SET_MANAGE_WEBEX_CALLING_IN_WXCC,
|
|
1787
|
+
}
|
|
1788
|
+
);
|
|
1789
|
+
this.scheduleFalsePublishRetry(retryAttempt + 1, options);
|
|
1790
|
+
}
|
|
1791
|
+
}, ContactCenter.WXAPP_FALSE_PUBLISH_RETRY_DELAY_MS);
|
|
1792
|
+
}
|
|
1793
|
+
|
|
1794
|
+
/**
|
|
1795
|
+
* Best-effort rollback when usersub true was published but wxApp setup did not complete.
|
|
1796
|
+
* @private
|
|
1797
|
+
*/
|
|
1798
|
+
private async revertWxAppCrossClientPublish(): Promise<void> {
|
|
1799
|
+
try {
|
|
1800
|
+
await this.publishAnswerOnWebexCrossClientState(false, {force: true});
|
|
1801
|
+
} catch (error) {
|
|
1802
|
+
LoggerProxy.error(
|
|
1803
|
+
`Failed to publish compensating answer-calls-on-wxcc false during wxApp rollback: ${error}`,
|
|
1804
|
+
{
|
|
1805
|
+
module: CC_FILE,
|
|
1806
|
+
method: METHODS.SET_MANAGE_WEBEX_CALLING_IN_WXCC,
|
|
1807
|
+
}
|
|
1808
|
+
);
|
|
1809
|
+
this.scheduleCompensatingFalsePublishRetry();
|
|
1810
|
+
}
|
|
1811
|
+
|
|
1812
|
+
this.webexCrossClientService.teardown();
|
|
1813
|
+
this.wxAppTelephonyMercurySync.unsubscribe();
|
|
1814
|
+
await this.releaseWxAppMercuryResources();
|
|
1815
|
+
}
|
|
1816
|
+
|
|
1817
|
+
private async ensureWxAppDeviceRegistered(): Promise<void> {
|
|
1818
|
+
const device = this.$webex.internal.device;
|
|
1819
|
+
|
|
1820
|
+
if (device && !device.registered && device.register) {
|
|
1821
|
+
await device.register();
|
|
1822
|
+
this.wxAppDeviceRegisteredByCc = true;
|
|
1823
|
+
LoggerProxy.log('WxApp: device registered for cross-client publish', {
|
|
1824
|
+
module: CC_FILE,
|
|
1825
|
+
method: METHODS.ENSURE_WXAPP_MERCURY_CONNECTED,
|
|
1826
|
+
});
|
|
1827
|
+
}
|
|
1828
|
+
}
|
|
1829
|
+
|
|
1830
|
+
private async ensureWxAppMercuryConnected(): Promise<void> {
|
|
1831
|
+
const mercury = this.$webex.internal.mercury;
|
|
1832
|
+
|
|
1833
|
+
await this.ensureWxAppDeviceRegistered();
|
|
1834
|
+
|
|
1835
|
+
if (mercury && !mercury.connected) {
|
|
1836
|
+
await mercury.connect();
|
|
1837
|
+
this.wxAppMercuryConnectedByCc = true;
|
|
1838
|
+
LoggerProxy.log('WxApp mute sync: mercury connected', {
|
|
1839
|
+
module: CC_FILE,
|
|
1840
|
+
method: METHODS.ENSURE_WXAPP_MERCURY_CONNECTED,
|
|
1841
|
+
});
|
|
1842
|
+
}
|
|
1843
|
+
}
|
|
1844
|
+
|
|
1845
|
+
/**
|
|
1846
|
+
* Disconnects Mercury and unregisters the device when wxApp mute sync opened them.
|
|
1847
|
+
* @private
|
|
1848
|
+
*/
|
|
1849
|
+
private async releaseWxAppMercuryResources(): Promise<void> {
|
|
1850
|
+
const mercury = this.$webex.internal.mercury;
|
|
1851
|
+
const device = this.$webex.internal.device;
|
|
1852
|
+
|
|
1853
|
+
if (this.wxAppMercuryConnectedByCc && mercury?.connected) {
|
|
1854
|
+
try {
|
|
1855
|
+
await mercury.disconnect();
|
|
1856
|
+
this.wxAppMercuryConnectedByCc = false;
|
|
1857
|
+
LoggerProxy.log('WxApp mute sync: mercury disconnected', {
|
|
1858
|
+
module: CC_FILE,
|
|
1859
|
+
method: METHODS.ENSURE_WXAPP_MERCURY_CONNECTED,
|
|
1860
|
+
});
|
|
1861
|
+
} catch (error) {
|
|
1862
|
+
LoggerProxy.error(`Failed to disconnect wxApp Mercury: ${error}`, {
|
|
1863
|
+
module: CC_FILE,
|
|
1864
|
+
method: METHODS.ENSURE_WXAPP_MERCURY_CONNECTED,
|
|
1865
|
+
});
|
|
1866
|
+
}
|
|
1867
|
+
}
|
|
1868
|
+
|
|
1869
|
+
if (this.wxAppDeviceRegisteredByCc && device?.registered && device.unregister) {
|
|
1870
|
+
try {
|
|
1871
|
+
// @ts-ignore
|
|
1872
|
+
await device.unregister();
|
|
1873
|
+
this.wxAppDeviceRegisteredByCc = false;
|
|
1874
|
+
LoggerProxy.log('WxApp mute sync: device unregistered', {
|
|
1875
|
+
module: CC_FILE,
|
|
1876
|
+
method: METHODS.ENSURE_WXAPP_MERCURY_CONNECTED,
|
|
1877
|
+
});
|
|
1878
|
+
} catch (error) {
|
|
1879
|
+
LoggerProxy.error(`Failed to unregister wxApp device: ${error}`, {
|
|
1880
|
+
module: CC_FILE,
|
|
1881
|
+
method: METHODS.ENSURE_WXAPP_MERCURY_CONNECTED,
|
|
1882
|
+
});
|
|
1883
|
+
}
|
|
1884
|
+
} else if (this.wxAppDeviceRegisteredByCc) {
|
|
1885
|
+
this.wxAppDeviceRegisteredByCc = false;
|
|
1886
|
+
}
|
|
1887
|
+
}
|
|
1888
|
+
|
|
1889
|
+
/**
|
|
1890
|
+
* Clears wxApp runtime state and feature-owned resources. Publish failures are logged;
|
|
1891
|
+
* optional rethrow for deregister when callers need to surface usersub errors.
|
|
1892
|
+
* @private
|
|
1893
|
+
*/
|
|
1894
|
+
private async teardownWxAppLocalState(options?: {
|
|
1895
|
+
rethrowPublishError?: boolean;
|
|
1896
|
+
clearInitFlag?: boolean;
|
|
1897
|
+
}): Promise<{publishError?: unknown}> {
|
|
1898
|
+
this.clearWxAppFalsePublishRetryTimer();
|
|
1899
|
+
let publishError: unknown;
|
|
1900
|
+
|
|
1901
|
+
try {
|
|
1902
|
+
const shouldForceFalsePublish =
|
|
1903
|
+
this.isWxBetterTogetherEnabled() || this.webexCrossClientService.isAnswerCallsStateActive();
|
|
1904
|
+
|
|
1905
|
+
await this.publishAnswerOnWebexCrossClientState(false, {
|
|
1906
|
+
force: shouldForceFalsePublish,
|
|
1907
|
+
});
|
|
1908
|
+
} catch (error) {
|
|
1909
|
+
publishError = error;
|
|
1910
|
+
LoggerProxy.error(
|
|
1911
|
+
`Failed to publish answer-calls-on-wxcc false during wxApp teardown: ${error}`,
|
|
1912
|
+
{
|
|
1913
|
+
module: CC_FILE,
|
|
1914
|
+
method: METHODS.SET_MANAGE_WEBEX_CALLING_IN_WXCC,
|
|
1915
|
+
}
|
|
1916
|
+
);
|
|
1917
|
+
}
|
|
1918
|
+
|
|
1919
|
+
this.webexCrossClientService.teardown();
|
|
1920
|
+
this.wxAppTelephonyMercurySync.unsubscribe();
|
|
1921
|
+
await this.releaseWxAppMercuryResources();
|
|
1922
|
+
|
|
1923
|
+
if (options?.clearInitFlag) {
|
|
1924
|
+
this.resetEnableWxBetterTogetherConfig();
|
|
1925
|
+
}
|
|
1926
|
+
|
|
1927
|
+
if (publishError) {
|
|
1928
|
+
this.scheduleCompensatingFalsePublishRetry();
|
|
1929
|
+
}
|
|
1930
|
+
|
|
1931
|
+
if (options?.rethrowPublishError && publishError) {
|
|
1932
|
+
throw publishError;
|
|
1933
|
+
}
|
|
1934
|
+
|
|
1935
|
+
return {publishError: publishError ?? undefined};
|
|
1936
|
+
}
|
|
1937
|
+
|
|
1938
|
+
private async ensureWxAppMercuryAndSubscribe(): Promise<void> {
|
|
1939
|
+
if (!this.isWxBetterTogetherEnabled()) {
|
|
1940
|
+
return;
|
|
1941
|
+
}
|
|
1942
|
+
|
|
1943
|
+
if (this.getCurrentStationLoginOption() === LoginOption.BROWSER) {
|
|
1944
|
+
return;
|
|
1945
|
+
}
|
|
1946
|
+
|
|
1947
|
+
const agentId = this.agentConfig?.agentId;
|
|
1948
|
+
if (!agentId) {
|
|
1949
|
+
LoggerProxy.error('Cannot subscribe wxApp mute sync: agentId unavailable', {
|
|
1950
|
+
module: CC_FILE,
|
|
1951
|
+
method: METHODS.SYNC_WXAPP_MUTE_FROM_MERCURY,
|
|
1952
|
+
});
|
|
1953
|
+
|
|
1954
|
+
this.metricsManager.trackEvent(
|
|
1955
|
+
METRIC_EVENT_NAMES.WXAPP_MERCURY_SUBSCRIBE_FAILED,
|
|
1956
|
+
{error: 'agentId unavailable'},
|
|
1957
|
+
['operational', 'behavioral']
|
|
1958
|
+
);
|
|
1959
|
+
|
|
1960
|
+
return;
|
|
1961
|
+
}
|
|
1962
|
+
|
|
1963
|
+
try {
|
|
1964
|
+
await this.ensureWxAppMercuryConnected();
|
|
1965
|
+
this.wxAppTelephonyMercurySync.subscribe(agentId, (callId, muted) => {
|
|
1966
|
+
this.taskManager.applyWxAppMuteStateFromSync(callId, muted);
|
|
1967
|
+
});
|
|
1968
|
+
} catch (error) {
|
|
1969
|
+
LoggerProxy.error(`Failed to ensure wxApp Mercury mute sync: ${error}`, {
|
|
1970
|
+
module: CC_FILE,
|
|
1971
|
+
method: METHODS.SYNC_WXAPP_MUTE_FROM_MERCURY,
|
|
1972
|
+
});
|
|
1973
|
+
this.metricsManager.trackEvent(
|
|
1974
|
+
METRIC_EVENT_NAMES.WXAPP_MERCURY_SUBSCRIBE_FAILED,
|
|
1975
|
+
{error: error instanceof Error ? error.toString() : String(error)},
|
|
1976
|
+
['operational', 'behavioral']
|
|
1977
|
+
);
|
|
1978
|
+
this.wxAppTelephonyMercurySync.unsubscribe();
|
|
1979
|
+
await this.releaseWxAppMercuryResources();
|
|
1980
|
+
throw error;
|
|
1981
|
+
}
|
|
1982
|
+
}
|
|
1983
|
+
|
|
1984
|
+
private async publishAnswerOnWebexCrossClientState(
|
|
1985
|
+
enable: boolean,
|
|
1986
|
+
options?: {force?: boolean}
|
|
1987
|
+
): Promise<void> {
|
|
1988
|
+
if (enable && !this.isWxBetterTogetherEnabled()) {
|
|
1989
|
+
return;
|
|
1990
|
+
}
|
|
1991
|
+
|
|
1992
|
+
if (!enable && !options?.force && !this.webexCrossClientService.isAnswerCallsStateActive()) {
|
|
1993
|
+
return;
|
|
1994
|
+
}
|
|
1995
|
+
|
|
1996
|
+
const userId = this.$webex.internal.device?.userId;
|
|
1997
|
+
if (!userId) {
|
|
1998
|
+
if (enable && this.isWxBetterTogetherEnabled()) {
|
|
1999
|
+
this.metricsManager.trackEvent(
|
|
2000
|
+
METRIC_EVENT_NAMES.WXAPP_USERSUB_PUBLISH_FAILED,
|
|
2001
|
+
{
|
|
2002
|
+
enableWxBetterTogether: true,
|
|
2003
|
+
skipReason: 'user_id_unavailable',
|
|
2004
|
+
error: 'User ID is unavailable for cross-client publish',
|
|
2005
|
+
},
|
|
2006
|
+
['operational', 'behavioral']
|
|
2007
|
+
);
|
|
2008
|
+
}
|
|
2009
|
+
|
|
2010
|
+
return;
|
|
2011
|
+
}
|
|
2012
|
+
|
|
2013
|
+
await this.webexCrossClientService.setManageWebexCallingInWxcc(enable, {
|
|
2014
|
+
userId,
|
|
2015
|
+
trackPublishMetrics: true,
|
|
2016
|
+
});
|
|
2017
|
+
|
|
2018
|
+
if (enable) {
|
|
2019
|
+
this.clearWxAppFalsePublishRetryTimer();
|
|
2020
|
+
}
|
|
2021
|
+
}
|
|
2022
|
+
|
|
1380
2023
|
/**
|
|
1381
2024
|
* Initializes event listeners for the Contact Center service
|
|
1382
2025
|
* Sets up handlers for connection state changes and other core events
|
|
@@ -1481,6 +2124,8 @@ export default class ContactCenter extends WebexPlugin implements IContactCenter
|
|
|
1481
2124
|
this.agentConfig.lastStateAuxCodeId = auxCodeId;
|
|
1482
2125
|
this.agentConfig.isAgentLoggedIn = true;
|
|
1483
2126
|
|
|
2127
|
+
await this.ensureWxAppPostStationLogin();
|
|
2128
|
+
|
|
1484
2129
|
LoggerProxy.log(
|
|
1485
2130
|
`Silent relogin process completed successfully with login Option: ${reLoginResponse.data.deviceType} teamId: ${reLoginResponse.data.teamId}`,
|
|
1486
2131
|
{
|
|
@@ -2199,8 +2844,8 @@ export default class ContactCenter extends WebexPlugin implements IContactCenter
|
|
|
2199
2844
|
}
|
|
2200
2845
|
|
|
2201
2846
|
/**
|
|
2202
|
-
* Returns paginated entry points
|
|
2203
|
-
*
|
|
2847
|
+
* Returns paginated entry points using the EntryPoint service defaults.
|
|
2848
|
+
* Existing request parameters can override those defaults.
|
|
2204
2849
|
* @public
|
|
2205
2850
|
*/
|
|
2206
2851
|
public async getEntryPoints(
|
|
@@ -2210,8 +2855,8 @@ export default class ContactCenter extends WebexPlugin implements IContactCenter
|
|
|
2210
2855
|
}
|
|
2211
2856
|
|
|
2212
2857
|
/**
|
|
2213
|
-
* Returns paginated contact service queues
|
|
2214
|
-
*
|
|
2858
|
+
* Returns paginated contact service queues using the Queue service defaults.
|
|
2859
|
+
* Existing request parameters can override those defaults.
|
|
2215
2860
|
* @public
|
|
2216
2861
|
*/
|
|
2217
2862
|
public async getQueues(
|