@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.
Files changed (307) hide show
  1. package/.sdd/manifest.json +884 -0
  2. package/AGENTS.md +94 -0
  3. package/ai-docs/ARCHITECTURE.md +168 -0
  4. package/ai-docs/CONTRACTS.md +51 -0
  5. package/ai-docs/GETTING_STARTED.md +168 -0
  6. package/ai-docs/GLOSSARY.md +43 -0
  7. package/ai-docs/README.md +138 -0
  8. package/ai-docs/REVIEW_CHECKLIST.md +41 -0
  9. package/ai-docs/RULES.md +444 -0
  10. package/ai-docs/SECURITY.md +52 -0
  11. package/ai-docs/SERVICE_STATE.md +48 -0
  12. package/ai-docs/SPEC_INDEX.md +65 -0
  13. package/ai-docs/adr/0001-spec-source-policy.md +55 -0
  14. package/ai-docs/adr/README.md +8 -0
  15. package/ai-docs/adr/_adr-template.md +31 -0
  16. package/ai-docs/contact-center-spec.md +359 -0
  17. package/ai-docs/features/consult-transfer-list-policy/spec/feature-spec.md +362 -0
  18. package/ai-docs/features/generated-spec-conformance-fidelity-remediation/spec/feature-spec.md +117 -0
  19. package/ai-docs/features/residual-warning-coverage-completion/spec/feature-spec.md +203 -0
  20. package/ai-docs/features/validator-code-fidelity-drift-fix/spec/feature-spec.md +315 -0
  21. package/ai-docs/patterns/event-driven-patterns.md +485 -0
  22. package/ai-docs/patterns/testing-patterns.md +480 -0
  23. package/ai-docs/patterns/typescript-patterns.md +365 -0
  24. package/ai-docs/templates/README.md +102 -0
  25. package/ai-docs/templates/documentation/create-agents-md.md +240 -0
  26. package/ai-docs/templates/documentation/create-architecture-md.md +295 -0
  27. package/ai-docs/templates/existing-service/bug-fix.md +254 -0
  28. package/ai-docs/templates/existing-service/feature-enhancement.md +450 -0
  29. package/ai-docs/templates/new-method/00-master.md +80 -0
  30. package/ai-docs/templates/new-method/01-requirements.md +232 -0
  31. package/ai-docs/templates/new-method/02-implementation.md +295 -0
  32. package/ai-docs/templates/new-method/03-tests.md +201 -0
  33. package/ai-docs/templates/new-method/04-validation.md +141 -0
  34. package/ai-docs/templates/new-service/00-master.md +109 -0
  35. package/ai-docs/templates/new-service/01-pre-questions.md +159 -0
  36. package/ai-docs/templates/new-service/02-code-generation.md +346 -0
  37. package/ai-docs/templates/new-service/03-integration.md +178 -0
  38. package/ai-docs/templates/new-service/04-test-generation.md +205 -0
  39. package/ai-docs/templates/new-service/05-validation.md +145 -0
  40. package/dist/cc.js +808 -40
  41. package/dist/cc.js.map +1 -1
  42. package/dist/config.js +13 -0
  43. package/dist/config.js.map +1 -1
  44. package/dist/constants.js +27 -3
  45. package/dist/constants.js.map +1 -1
  46. package/dist/index.js +20 -5
  47. package/dist/index.js.map +1 -1
  48. package/dist/metrics/MetricsManager.js +16 -0
  49. package/dist/metrics/MetricsManager.js.map +1 -1
  50. package/dist/metrics/behavioral-events.js +205 -0
  51. package/dist/metrics/behavioral-events.js.map +1 -1
  52. package/dist/metrics/constants.js +43 -4
  53. package/dist/metrics/constants.js.map +1 -1
  54. package/dist/services/AddressBook.js +18 -15
  55. package/dist/services/AddressBook.js.map +1 -1
  56. package/dist/services/AnswerCallOnWebexService.js +202 -0
  57. package/dist/services/AnswerCallOnWebexService.js.map +1 -0
  58. package/dist/services/ApiAiAssistant.js +153 -8
  59. package/dist/services/ApiAiAssistant.js.map +1 -1
  60. package/dist/services/EntryPoint.js +46 -68
  61. package/dist/services/EntryPoint.js.map +1 -1
  62. package/dist/services/Queue.js +27 -22
  63. package/dist/services/Queue.js.map +1 -1
  64. package/dist/services/UserPreference.js +427 -0
  65. package/dist/services/UserPreference.js.map +1 -0
  66. package/dist/services/WebexCrossClientService.js +222 -0
  67. package/dist/services/WebexCrossClientService.js.map +1 -0
  68. package/dist/services/WxAppTelephonyMercurySync.js +108 -0
  69. package/dist/services/WxAppTelephonyMercurySync.js.map +1 -0
  70. package/dist/services/config/Util.js +6 -3
  71. package/dist/services/config/Util.js.map +1 -1
  72. package/dist/services/config/constants.js +33 -8
  73. package/dist/services/config/constants.js.map +1 -1
  74. package/dist/services/config/types.js +53 -9
  75. package/dist/services/config/types.js.map +1 -1
  76. package/dist/services/core/Err.js.map +1 -1
  77. package/dist/services/core/Utils.js +107 -32
  78. package/dist/services/core/Utils.js.map +1 -1
  79. package/dist/services/core/WebexRequest.js +6 -2
  80. package/dist/services/core/WebexRequest.js.map +1 -1
  81. package/dist/services/core/aqm-reqs.js +28 -14
  82. package/dist/services/core/aqm-reqs.js.map +1 -1
  83. package/dist/services/core/types.js.map +1 -1
  84. package/dist/services/core/websocket/WebSocketManager.js +2 -1
  85. package/dist/services/core/websocket/WebSocketManager.js.map +1 -1
  86. package/dist/services/core/websocket/types.js.map +1 -1
  87. package/dist/services/index.js +1 -1
  88. package/dist/services/index.js.map +1 -1
  89. package/dist/services/task/Task.js +754 -0
  90. package/dist/services/task/Task.js.map +1 -0
  91. package/dist/services/task/TaskFactory.js +49 -0
  92. package/dist/services/task/TaskFactory.js.map +1 -0
  93. package/dist/services/task/TaskManager.js +1053 -520
  94. package/dist/services/task/TaskManager.js.map +1 -1
  95. package/dist/services/task/TaskUtils.js +211 -27
  96. package/dist/services/task/TaskUtils.js.map +1 -1
  97. package/dist/services/task/WebexCallingUtils.js +70 -0
  98. package/dist/services/task/WebexCallingUtils.js.map +1 -0
  99. package/dist/services/task/constants.js +12 -2
  100. package/dist/services/task/constants.js.map +1 -1
  101. package/dist/services/task/contact.js +29 -0
  102. package/dist/services/task/contact.js.map +1 -1
  103. package/dist/services/task/dialer.js +78 -0
  104. package/dist/services/task/dialer.js.map +1 -1
  105. package/dist/services/task/digital/Digital.js +78 -0
  106. package/dist/services/task/digital/Digital.js.map +1 -0
  107. package/dist/services/task/state-machine/TaskStateMachine.js +954 -0
  108. package/dist/services/task/state-machine/TaskStateMachine.js.map +1 -0
  109. package/dist/services/task/state-machine/actions.js +572 -0
  110. package/dist/services/task/state-machine/actions.js.map +1 -0
  111. package/dist/services/task/state-machine/constants.js +161 -0
  112. package/dist/services/task/state-machine/constants.js.map +1 -0
  113. package/dist/services/task/state-machine/guards.js +379 -0
  114. package/dist/services/task/state-machine/guards.js.map +1 -0
  115. package/dist/services/task/state-machine/index.js +53 -0
  116. package/dist/services/task/state-machine/index.js.map +1 -0
  117. package/dist/services/task/state-machine/types.js +54 -0
  118. package/dist/services/task/state-machine/types.js.map +1 -0
  119. package/dist/services/task/state-machine/uiControlsComputer.js +703 -0
  120. package/dist/services/task/state-machine/uiControlsComputer.js.map +1 -0
  121. package/dist/services/task/taskDataNormalizer.js +99 -0
  122. package/dist/services/task/taskDataNormalizer.js.map +1 -0
  123. package/dist/services/task/types.js +228 -5
  124. package/dist/services/task/types.js.map +1 -1
  125. package/dist/services/task/voice/Voice.js +1447 -0
  126. package/dist/services/task/voice/Voice.js.map +1 -0
  127. package/dist/services/task/voice/WebRTC.js +152 -0
  128. package/dist/services/task/voice/WebRTC.js.map +1 -0
  129. package/dist/services/task/voice/wxAppVoiceMethods.js +354 -0
  130. package/dist/services/task/voice/wxAppVoiceMethods.js.map +1 -0
  131. package/dist/services/wxAppDiagnosticLogging.js +122 -0
  132. package/dist/services/wxAppDiagnosticLogging.js.map +1 -0
  133. package/dist/services/wxAppTelephonyUtils.js +19 -0
  134. package/dist/services/wxAppTelephonyUtils.js.map +1 -0
  135. package/dist/types/cc.d.ts +172 -5
  136. package/dist/types/config.d.ts +13 -0
  137. package/dist/types/constants.d.ts +25 -1
  138. package/dist/types/index.d.ts +24 -7
  139. package/dist/types/metrics/MetricsManager.d.ts +6 -0
  140. package/dist/types/metrics/constants.d.ts +38 -1
  141. package/dist/types/services/AddressBook.d.ts +2 -1
  142. package/dist/types/services/AnswerCallOnWebexService.d.ts +38 -0
  143. package/dist/types/services/ApiAiAssistant.d.ts +22 -4
  144. package/dist/types/services/EntryPoint.d.ts +7 -5
  145. package/dist/types/services/Queue.d.ts +5 -3
  146. package/dist/types/services/UserPreference.d.ts +118 -0
  147. package/dist/types/services/WebexCrossClientService.d.ts +32 -0
  148. package/dist/types/services/WxAppTelephonyMercurySync.d.ts +28 -0
  149. package/dist/types/services/config/constants.d.ts +29 -5
  150. package/dist/types/services/config/types.d.ts +184 -10
  151. package/dist/types/services/core/Err.d.ts +6 -0
  152. package/dist/types/services/core/Utils.d.ts +33 -13
  153. package/dist/types/services/core/WebexRequest.d.ts +1 -0
  154. package/dist/types/services/core/types.d.ts +2 -0
  155. package/dist/types/services/core/websocket/WebSocketManager.d.ts +1 -0
  156. package/dist/types/services/core/websocket/types.d.ts +1 -1
  157. package/dist/types/services/index.d.ts +1 -1
  158. package/dist/types/services/task/Task.d.ts +175 -0
  159. package/dist/types/services/task/TaskFactory.d.ts +13 -0
  160. package/dist/types/services/task/TaskUtils.d.ts +48 -2
  161. package/dist/types/services/task/WebexCallingUtils.d.ts +11 -0
  162. package/dist/types/services/task/constants.d.ts +10 -0
  163. package/dist/types/services/task/contact.d.ts +4 -0
  164. package/dist/types/services/task/dialer.d.ts +30 -0
  165. package/dist/types/services/task/digital/Digital.d.ts +22 -0
  166. package/dist/types/services/task/state-machine/TaskStateMachine.d.ts +1356 -0
  167. package/dist/types/services/task/state-machine/actions.d.ts +10 -0
  168. package/dist/types/services/task/state-machine/constants.d.ts +107 -0
  169. package/dist/types/services/task/state-machine/guards.d.ts +103 -0
  170. package/dist/types/services/task/state-machine/index.d.ts +13 -0
  171. package/dist/types/services/task/state-machine/types.d.ts +277 -0
  172. package/dist/types/services/task/state-machine/uiControlsComputer.d.ts +9 -0
  173. package/dist/types/services/task/taskDataNormalizer.d.ts +10 -0
  174. package/dist/types/services/task/types.d.ts +680 -66
  175. package/dist/types/services/task/voice/Voice.d.ts +227 -0
  176. package/dist/types/services/task/voice/WebRTC.d.ts +53 -0
  177. package/dist/types/services/task/voice/wxAppVoiceMethods.d.ts +55 -0
  178. package/dist/types/services/wxAppDiagnosticLogging.d.ts +51 -0
  179. package/dist/types/services/wxAppTelephonyUtils.d.ts +5 -0
  180. package/dist/types/types.d.ts +149 -8
  181. package/dist/types/utils/PageCache.d.ts +20 -3
  182. package/dist/types/webex.d.ts +1 -0
  183. package/dist/types.js +125 -4
  184. package/dist/types.js.map +1 -1
  185. package/dist/utils/PageCache.js +19 -5
  186. package/dist/utils/PageCache.js.map +1 -1
  187. package/dist/webex.js +14 -2
  188. package/dist/webex.js.map +1 -1
  189. package/package.json +16 -12
  190. package/src/cc.ts +986 -42
  191. package/src/config.ts +13 -0
  192. package/src/constants.ts +25 -1
  193. package/src/index.ts +25 -5
  194. package/src/metrics/MetricsManager.ts +16 -0
  195. package/src/metrics/ai-docs/AGENTS.md +350 -0
  196. package/src/metrics/ai-docs/ARCHITECTURE.md +338 -0
  197. package/src/metrics/ai-docs/metrics-spec.md +922 -0
  198. package/src/metrics/behavioral-events.ts +212 -0
  199. package/src/metrics/constants.ts +47 -4
  200. package/src/services/AddressBook.ts +17 -6
  201. package/src/services/AnswerCallOnWebexService.ts +239 -0
  202. package/src/services/ApiAiAssistant.ts +203 -8
  203. package/src/services/EntryPoint.ts +59 -60
  204. package/src/services/Queue.ts +29 -12
  205. package/src/services/UserPreference.ts +509 -0
  206. package/src/services/WebexCrossClientService.ts +293 -0
  207. package/src/services/WxAppTelephonyMercurySync.ts +142 -0
  208. package/src/services/agent/ai-docs/AGENTS.md +240 -0
  209. package/src/services/agent/ai-docs/ARCHITECTURE.md +304 -0
  210. package/src/services/agent/ai-docs/agent-spec.md +505 -0
  211. package/src/services/ai-docs/AGENTS.md +386 -0
  212. package/src/services/ai-docs/services-spec.md +497 -0
  213. package/src/services/config/Util.ts +6 -3
  214. package/src/services/config/ai-docs/AGENTS.md +255 -0
  215. package/src/services/config/ai-docs/ARCHITECTURE.md +426 -0
  216. package/src/services/config/ai-docs/config-spec.md +675 -0
  217. package/src/services/config/constants.ts +35 -7
  218. package/src/services/config/types.ts +186 -11
  219. package/src/services/core/Err.ts +3 -0
  220. package/src/services/core/Utils.ts +123 -37
  221. package/src/services/core/WebexRequest.ts +3 -1
  222. package/src/services/core/ai-docs/AGENTS.md +381 -0
  223. package/src/services/core/ai-docs/ARCHITECTURE.md +698 -0
  224. package/src/services/core/ai-docs/core-spec.md +787 -0
  225. package/src/services/core/aqm-reqs.ts +30 -15
  226. package/src/services/core/types.ts +2 -0
  227. package/src/services/core/websocket/WebSocketManager.ts +2 -0
  228. package/src/services/core/websocket/types.ts +1 -1
  229. package/src/services/index.ts +1 -1
  230. package/src/services/task/Task.ts +908 -0
  231. package/src/services/task/TaskFactory.ts +60 -0
  232. package/src/services/task/TaskManager.ts +1239 -608
  233. package/src/services/task/TaskUtils.ts +303 -25
  234. package/src/services/task/WebexCallingUtils.ts +136 -0
  235. package/src/services/task/ai-docs/AGENTS.md +457 -0
  236. package/src/services/task/ai-docs/ARCHITECTURE.md +595 -0
  237. package/src/services/task/ai-docs/task-spec.md +1470 -0
  238. package/src/services/task/constants.ts +10 -0
  239. package/src/services/task/contact.ts +30 -0
  240. package/src/services/task/dialer.ts +80 -0
  241. package/src/services/task/digital/Digital.ts +97 -0
  242. package/src/services/task/state-machine/TaskStateMachine.ts +1293 -0
  243. package/src/services/task/state-machine/actions.ts +741 -0
  244. package/src/services/task/state-machine/ai-docs/AGENTS.md +460 -0
  245. package/src/services/task/state-machine/ai-docs/ARCHITECTURE.md +1145 -0
  246. package/src/services/task/state-machine/ai-docs/task-state-machine-spec.md +2207 -0
  247. package/src/services/task/state-machine/constants.ts +172 -0
  248. package/src/services/task/state-machine/guards.ts +442 -0
  249. package/src/services/task/state-machine/index.ts +28 -0
  250. package/src/services/task/state-machine/types.ts +258 -0
  251. package/src/services/task/state-machine/uiControlsComputer.ts +1135 -0
  252. package/src/services/task/taskDataNormalizer.ts +137 -0
  253. package/src/services/task/types.ts +819 -70
  254. package/src/services/task/voice/Voice.ts +1809 -0
  255. package/src/services/task/voice/WebRTC.ts +191 -0
  256. package/src/services/task/voice/wxAppVoiceMethods.ts +516 -0
  257. package/src/services/wxAppDiagnosticLogging.ts +174 -0
  258. package/src/services/wxAppTelephonyUtils.ts +14 -0
  259. package/src/types.ts +199 -11
  260. package/src/utils/AGENTS.md +289 -0
  261. package/src/utils/PageCache.ts +38 -5
  262. package/src/utils/ai-docs/utils-spec.md +391 -0
  263. package/src/webex.js +2 -0
  264. package/test/unit/spec/cc.ts +1947 -124
  265. package/test/unit/spec/logger-proxy.ts +70 -0
  266. package/test/unit/spec/metrics/MetricsManager.ts +25 -0
  267. package/test/unit/spec/metrics/behavioral-events.ts +60 -0
  268. package/test/unit/spec/services/AddressBook.ts +37 -6
  269. package/test/unit/spec/services/AnswerCallOnWebexService.ts +264 -0
  270. package/test/unit/spec/services/ApiAiAssistant.ts +178 -20
  271. package/test/unit/spec/services/EntryPoint.ts +87 -40
  272. package/test/unit/spec/services/Queue.ts +123 -12
  273. package/test/unit/spec/services/UserPreference.ts +401 -0
  274. package/test/unit/spec/services/WebCallingService.ts +7 -1
  275. package/test/unit/spec/services/WebexCrossClientService.ts +467 -0
  276. package/test/unit/spec/services/WxAppTelephonyMercurySync.ts +136 -0
  277. package/test/unit/spec/services/config/Util.ts +85 -0
  278. package/test/unit/spec/services/config/index.ts +30 -30
  279. package/test/unit/spec/services/core/Utils.ts +425 -8
  280. package/test/unit/spec/services/core/WebexRequest.ts +3 -1
  281. package/test/unit/spec/services/core/aqm-reqs.ts +113 -1
  282. package/test/unit/spec/services/core/websocket/WebSocketManager.ts +66 -40
  283. package/test/unit/spec/services/task/AutoWrapup.ts +63 -0
  284. package/test/unit/spec/services/task/Task.ts +677 -0
  285. package/test/unit/spec/services/task/TaskFactory.ts +99 -0
  286. package/test/unit/spec/services/task/TaskManager.ts +1972 -1549
  287. package/test/unit/spec/services/task/TaskUtils.ts +235 -0
  288. package/test/unit/spec/services/task/WebexCallingUtils.ts +153 -0
  289. package/test/unit/spec/services/task/contact.ts +33 -0
  290. package/test/unit/spec/services/task/dialer.ts +190 -0
  291. package/test/unit/spec/services/task/digital/Digital.ts +105 -0
  292. package/test/unit/spec/services/task/state-machine/TaskStateMachine.ts +3459 -0
  293. package/test/unit/spec/services/task/state-machine/guards.ts +839 -0
  294. package/test/unit/spec/services/task/state-machine/types.ts +18 -0
  295. package/test/unit/spec/services/task/state-machine/uiControlsComputer.ts +3101 -0
  296. package/test/unit/spec/services/task/taskTestUtils.ts +87 -0
  297. package/test/unit/spec/services/task/voice/Voice.ts +1903 -0
  298. package/test/unit/spec/services/task/voice/WebRTC.ts +235 -0
  299. package/test/unit/spec/services/task/voice/wxAppVoiceMethods.ts +603 -0
  300. package/test/unit/spec/services/wxAppDiagnosticLogging.ts +143 -0
  301. package/umd/contact-center.min.js +2 -2
  302. package/umd/contact-center.min.js.map +1 -1
  303. package/dist/services/task/index.js +0 -1525
  304. package/dist/services/task/index.js.map +0 -1
  305. package/dist/types/services/task/index.d.ts +0 -650
  306. package/src/services/task/index.ts +0 -1801
  307. 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 = payload => {
373
- this.taskManager.handleRealtimeWebsocketEvent(payload);
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.info('Starting CC SDK registration', {
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
- ...data
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: data.mediaType,
589
- buddyAgentState: data.state,
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: data.mediaType,
603
- buddyAgentState: data.state
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.info('Connecting to websocket', {
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
- if (this.agentConfig.aiFeature?.realtimeTranscripts?.enable) {
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
- await this.services.rtdWebSocketManager.initWebSocket({
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 during RTD websocket setup: ${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
- _loggerProxy.default.info('Starting agent station login', {
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 && !(0, _Utils.isValidDialNumber)(data.dialNumber, dialPlanEntries)) {
726
- const error = new Error('INVALID_DIAL_NUMBER');
727
- // @ts-ignore - adding custom key to the error object
728
- error.details = {
729
- data: {
730
- reason: 'INVALID_DIAL_NUMBER'
731
- }
732
- };
733
- throw error;
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
- dialNumber: data.loginOption === _types.LoginOption.BROWSER ? this.agentConfig.agentId : data.dialNumber,
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: this.getDeviceId(data.loginOption, data.dialNumber),
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.info('event=handleConnectionLost | Connection lost', {
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.info('event=handleConnectionReconnect | Connection reconnected attempting to request silent relogin', {
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.info('Starting silent relogin process', {
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.info('event=requestAutoStateChange | Requesting state change to available on socket reconnect', {
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
- // TODO: https://jira-eng-gpk2.cisco.com/jira/browse/SPARK-626777 Implement the de-register method and close the listener there
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 for the organization.
1652
- * Thin wrapper around internal EntryPoint instance.
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 for the organization.
1661
- * Thin wrapper around internal Queue instance.
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 = {}) {