@webex/contact-center 3.12.0-next.16 → 3.12.0-next.161

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