@webex/contact-center 3.11.0 → 3.12.0-auth-prejoin-fetch.1

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 (325) hide show
  1. package/.sdd/manifest.json +883 -0
  2. package/AGENTS.md +94 -0
  3. package/ai-docs/ARCHITECTURE.md +168 -0
  4. package/ai-docs/CONTRACTS.md +50 -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 +818 -59
  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 +31 -3
  45. package/dist/constants.js.map +1 -1
  46. package/dist/index.js +27 -5
  47. package/dist/index.js.map +1 -1
  48. package/dist/metrics/behavioral-events.js +127 -0
  49. package/dist/metrics/behavioral-events.js.map +1 -1
  50. package/dist/metrics/constants.js +34 -3
  51. package/dist/metrics/constants.js.map +1 -1
  52. package/dist/services/AddressBook.js +18 -15
  53. package/dist/services/AddressBook.js.map +1 -1
  54. package/dist/services/AnswerCallOnWebexService.js +174 -0
  55. package/dist/services/AnswerCallOnWebexService.js.map +1 -0
  56. package/dist/services/ApiAiAssistant.js +318 -0
  57. package/dist/services/ApiAiAssistant.js.map +1 -0
  58. package/dist/services/EntryPoint.js +46 -68
  59. package/dist/services/EntryPoint.js.map +1 -1
  60. package/dist/services/Queue.js +27 -22
  61. package/dist/services/Queue.js.map +1 -1
  62. package/dist/services/UserPreference.js +427 -0
  63. package/dist/services/UserPreference.js.map +1 -0
  64. package/dist/services/WebexCrossClientService.js +171 -0
  65. package/dist/services/WebexCrossClientService.js.map +1 -0
  66. package/dist/services/WxAppTelephonyMercurySync.js +93 -0
  67. package/dist/services/WxAppTelephonyMercurySync.js.map +1 -0
  68. package/dist/services/agent/types.js.map +1 -1
  69. package/dist/services/config/Util.js +11 -4
  70. package/dist/services/config/Util.js.map +1 -1
  71. package/dist/services/config/constants.js +45 -8
  72. package/dist/services/config/constants.js.map +1 -1
  73. package/dist/services/config/index.js +41 -2
  74. package/dist/services/config/index.js.map +1 -1
  75. package/dist/services/config/types.js +70 -8
  76. package/dist/services/config/types.js.map +1 -1
  77. package/dist/services/constants.js +27 -1
  78. package/dist/services/constants.js.map +1 -1
  79. package/dist/services/core/Err.js.map +1 -1
  80. package/dist/services/core/Utils.js +122 -25
  81. package/dist/services/core/Utils.js.map +1 -1
  82. package/dist/services/core/WebexRequest.js +6 -2
  83. package/dist/services/core/WebexRequest.js.map +1 -1
  84. package/dist/services/core/aqm-reqs.js +119 -30
  85. package/dist/services/core/aqm-reqs.js.map +1 -1
  86. package/dist/services/core/types.js.map +1 -1
  87. package/dist/services/core/websocket/WebSocketManager.js +22 -6
  88. package/dist/services/core/websocket/WebSocketManager.js.map +1 -1
  89. package/dist/services/core/websocket/connection-service.js +3 -1
  90. package/dist/services/core/websocket/connection-service.js.map +1 -1
  91. package/dist/services/core/websocket/types.js.map +1 -1
  92. package/dist/services/index.js +6 -0
  93. package/dist/services/index.js.map +1 -1
  94. package/dist/services/task/Task.js +754 -0
  95. package/dist/services/task/Task.js.map +1 -0
  96. package/dist/services/task/TaskFactory.js +49 -0
  97. package/dist/services/task/TaskFactory.js.map +1 -0
  98. package/dist/services/task/TaskManager.js +1073 -447
  99. package/dist/services/task/TaskManager.js.map +1 -1
  100. package/dist/services/task/TaskUtils.js +220 -23
  101. package/dist/services/task/TaskUtils.js.map +1 -1
  102. package/dist/services/task/WebexCallingUtils.js +70 -0
  103. package/dist/services/task/WebexCallingUtils.js.map +1 -0
  104. package/dist/services/task/constants.js +26 -2
  105. package/dist/services/task/constants.js.map +1 -1
  106. package/dist/services/task/contact.js +29 -0
  107. package/dist/services/task/contact.js.map +1 -1
  108. package/dist/services/task/dialer.js +129 -0
  109. package/dist/services/task/dialer.js.map +1 -1
  110. package/dist/services/task/digital/Digital.js +78 -0
  111. package/dist/services/task/digital/Digital.js.map +1 -0
  112. package/dist/services/task/state-machine/TaskStateMachine.js +971 -0
  113. package/dist/services/task/state-machine/TaskStateMachine.js.map +1 -0
  114. package/dist/services/task/state-machine/actions.js +572 -0
  115. package/dist/services/task/state-machine/actions.js.map +1 -0
  116. package/dist/services/task/state-machine/constants.js +161 -0
  117. package/dist/services/task/state-machine/constants.js.map +1 -0
  118. package/dist/services/task/state-machine/guards.js +409 -0
  119. package/dist/services/task/state-machine/guards.js.map +1 -0
  120. package/dist/services/task/state-machine/index.js +53 -0
  121. package/dist/services/task/state-machine/index.js.map +1 -0
  122. package/dist/services/task/state-machine/types.js +54 -0
  123. package/dist/services/task/state-machine/types.js.map +1 -0
  124. package/dist/services/task/state-machine/uiControlsComputer.js +703 -0
  125. package/dist/services/task/state-machine/uiControlsComputer.js.map +1 -0
  126. package/dist/services/task/taskDataNormalizer.js +99 -0
  127. package/dist/services/task/taskDataNormalizer.js.map +1 -0
  128. package/dist/services/task/types.js +243 -5
  129. package/dist/services/task/types.js.map +1 -1
  130. package/dist/services/task/voice/Voice.js +1380 -0
  131. package/dist/services/task/voice/Voice.js.map +1 -0
  132. package/dist/services/task/voice/WebRTC.js +152 -0
  133. package/dist/services/task/voice/WebRTC.js.map +1 -0
  134. package/dist/services/task/voice/wxAppVoiceMethods.js +201 -0
  135. package/dist/services/task/voice/wxAppVoiceMethods.js.map +1 -0
  136. package/dist/services/wxAppTelephonyUtils.js +19 -0
  137. package/dist/services/wxAppTelephonyUtils.js.map +1 -0
  138. package/dist/types/cc.d.ts +967 -0
  139. package/dist/types/config.d.ts +79 -0
  140. package/dist/types/constants.d.ts +74 -0
  141. package/dist/types/index.d.ts +201 -0
  142. package/dist/types/logger-proxy.d.ts +71 -0
  143. package/dist/types/metrics/MetricsManager.d.ts +223 -0
  144. package/dist/types/metrics/behavioral-events.d.ts +29 -0
  145. package/dist/types/metrics/constants.d.ts +183 -0
  146. package/dist/types/services/AddressBook.d.ts +75 -0
  147. package/dist/types/services/AnswerCallOnWebexService.d.ts +37 -0
  148. package/dist/types/services/ApiAiAssistant.d.ts +49 -0
  149. package/dist/types/services/EntryPoint.d.ts +69 -0
  150. package/dist/types/services/Queue.d.ts +78 -0
  151. package/dist/types/services/UserPreference.d.ts +118 -0
  152. package/dist/types/services/WebCallingService.d.ts +1 -0
  153. package/dist/types/services/WebexCrossClientService.d.ts +28 -0
  154. package/dist/types/services/WxAppTelephonyMercurySync.d.ts +28 -0
  155. package/dist/types/services/agent/index.d.ts +46 -0
  156. package/dist/types/services/agent/types.d.ts +413 -0
  157. package/dist/types/services/config/Util.d.ts +20 -0
  158. package/dist/types/services/config/constants.d.ts +273 -0
  159. package/dist/types/services/config/index.d.ts +177 -0
  160. package/dist/types/services/config/types.d.ts +1381 -0
  161. package/dist/types/services/constants.d.ts +110 -0
  162. package/dist/types/services/core/Err.d.ts +127 -0
  163. package/dist/types/services/core/GlobalTypes.d.ts +58 -0
  164. package/dist/types/services/core/Utils.d.ts +121 -0
  165. package/dist/types/services/core/WebexRequest.d.ts +23 -0
  166. package/dist/types/services/core/aqm-reqs.d.ts +65 -0
  167. package/dist/types/services/core/constants.d.ts +99 -0
  168. package/dist/types/services/core/types.d.ts +49 -0
  169. package/dist/types/services/core/websocket/WebSocketManager.d.ts +36 -0
  170. package/dist/types/services/core/websocket/connection-service.d.ts +27 -0
  171. package/dist/types/services/core/websocket/keepalive.worker.d.ts +2 -0
  172. package/dist/types/services/core/websocket/types.d.ts +37 -0
  173. package/dist/types/services/index.d.ts +54 -0
  174. package/dist/types/services/task/AutoWrapup.d.ts +40 -0
  175. package/dist/types/services/task/Task.d.ts +175 -0
  176. package/dist/types/services/task/TaskFactory.d.ts +13 -0
  177. package/dist/types/services/task/TaskManager.d.ts +1 -0
  178. package/dist/types/services/task/TaskUtils.d.ts +138 -0
  179. package/dist/types/services/task/WebexCallingUtils.d.ts +11 -0
  180. package/dist/types/services/task/constants.d.ts +94 -0
  181. package/dist/types/services/task/contact.d.ts +73 -0
  182. package/dist/types/services/task/dialer.d.ts +73 -0
  183. package/dist/types/services/task/digital/Digital.d.ts +22 -0
  184. package/dist/types/services/task/state-machine/TaskStateMachine.d.ts +1398 -0
  185. package/dist/types/services/task/state-machine/actions.d.ts +10 -0
  186. package/dist/types/services/task/state-machine/constants.d.ts +107 -0
  187. package/dist/types/services/task/state-machine/guards.d.ts +103 -0
  188. package/dist/types/services/task/state-machine/index.d.ts +13 -0
  189. package/dist/types/services/task/state-machine/types.d.ts +277 -0
  190. package/dist/types/services/task/state-machine/uiControlsComputer.d.ts +9 -0
  191. package/dist/types/services/task/taskDataNormalizer.d.ts +10 -0
  192. package/dist/types/services/task/types.d.ts +1933 -0
  193. package/dist/types/services/task/voice/Voice.d.ts +223 -0
  194. package/dist/types/services/task/voice/WebRTC.d.ts +53 -0
  195. package/dist/types/services/task/voice/wxAppVoiceMethods.d.ts +52 -0
  196. package/dist/types/services/wxAppTelephonyUtils.d.ts +5 -0
  197. package/dist/types/types.d.ts +784 -0
  198. package/dist/types/utils/PageCache.d.ts +190 -0
  199. package/dist/types/webex-config.d.ts +53 -0
  200. package/dist/types/webex.d.ts +8 -0
  201. package/dist/types.js +137 -3
  202. package/dist/types.js.map +1 -1
  203. package/dist/utils/PageCache.js +19 -5
  204. package/dist/utils/PageCache.js.map +1 -1
  205. package/dist/webex.js +14 -2
  206. package/dist/webex.js.map +1 -1
  207. package/package.json +16 -12
  208. package/src/cc.ts +983 -60
  209. package/src/config.ts +13 -0
  210. package/src/constants.ts +29 -1
  211. package/src/index.ts +26 -5
  212. package/src/metrics/ai-docs/AGENTS.md +350 -0
  213. package/src/metrics/ai-docs/ARCHITECTURE.md +338 -0
  214. package/src/metrics/ai-docs/metrics-spec.md +860 -0
  215. package/src/metrics/behavioral-events.ts +134 -0
  216. package/src/metrics/constants.ts +39 -3
  217. package/src/services/AddressBook.ts +17 -6
  218. package/src/services/AnswerCallOnWebexService.ts +206 -0
  219. package/src/services/ApiAiAssistant.ts +412 -0
  220. package/src/services/EntryPoint.ts +59 -60
  221. package/src/services/Queue.ts +29 -12
  222. package/src/services/UserPreference.ts +509 -0
  223. package/src/services/WebexCrossClientService.ts +212 -0
  224. package/src/services/WxAppTelephonyMercurySync.ts +115 -0
  225. package/src/services/agent/ai-docs/AGENTS.md +240 -0
  226. package/src/services/agent/ai-docs/ARCHITECTURE.md +304 -0
  227. package/src/services/agent/ai-docs/agent-spec.md +504 -0
  228. package/src/services/agent/types.ts +1 -1
  229. package/src/services/ai-docs/AGENTS.md +386 -0
  230. package/src/services/ai-docs/services-spec.md +497 -0
  231. package/src/services/config/Util.ts +13 -2
  232. package/src/services/config/ai-docs/AGENTS.md +255 -0
  233. package/src/services/config/ai-docs/ARCHITECTURE.md +426 -0
  234. package/src/services/config/ai-docs/config-spec.md +675 -0
  235. package/src/services/config/constants.ts +47 -7
  236. package/src/services/config/index.ts +45 -1
  237. package/src/services/config/types.ts +253 -11
  238. package/src/services/constants.ts +29 -0
  239. package/src/services/core/Err.ts +4 -0
  240. package/src/services/core/Utils.ts +143 -30
  241. package/src/services/core/WebexRequest.ts +3 -1
  242. package/src/services/core/ai-docs/AGENTS.md +381 -0
  243. package/src/services/core/ai-docs/ARCHITECTURE.md +698 -0
  244. package/src/services/core/ai-docs/core-spec.md +787 -0
  245. package/src/services/core/aqm-reqs.ts +125 -32
  246. package/src/services/core/types.ts +2 -0
  247. package/src/services/core/websocket/WebSocketManager.ts +23 -6
  248. package/src/services/core/websocket/connection-service.ts +5 -1
  249. package/src/services/core/websocket/types.ts +1 -1
  250. package/src/services/index.ts +4 -0
  251. package/src/services/task/Task.ts +908 -0
  252. package/src/services/task/TaskFactory.ts +60 -0
  253. package/src/services/task/TaskManager.ts +1291 -513
  254. package/src/services/task/TaskUtils.ts +314 -24
  255. package/src/services/task/WebexCallingUtils.ts +136 -0
  256. package/src/services/task/ai-docs/AGENTS.md +457 -0
  257. package/src/services/task/ai-docs/ARCHITECTURE.md +595 -0
  258. package/src/services/task/ai-docs/task-spec.md +1469 -0
  259. package/src/services/task/constants.ts +26 -0
  260. package/src/services/task/contact.ts +30 -0
  261. package/src/services/task/dialer.ts +136 -1
  262. package/src/services/task/digital/Digital.ts +97 -0
  263. package/src/services/task/state-machine/TaskStateMachine.ts +1313 -0
  264. package/src/services/task/state-machine/actions.ts +741 -0
  265. package/src/services/task/state-machine/ai-docs/AGENTS.md +462 -0
  266. package/src/services/task/state-machine/ai-docs/ARCHITECTURE.md +1146 -0
  267. package/src/services/task/state-machine/ai-docs/task-state-machine-spec.md +2209 -0
  268. package/src/services/task/state-machine/constants.ts +172 -0
  269. package/src/services/task/state-machine/guards.ts +498 -0
  270. package/src/services/task/state-machine/index.ts +28 -0
  271. package/src/services/task/state-machine/types.ts +258 -0
  272. package/src/services/task/state-machine/uiControlsComputer.ts +1135 -0
  273. package/src/services/task/taskDataNormalizer.ts +137 -0
  274. package/src/services/task/types.ts +843 -70
  275. package/src/services/task/voice/Voice.ts +1720 -0
  276. package/src/services/task/voice/WebRTC.ts +191 -0
  277. package/src/services/task/voice/wxAppVoiceMethods.ts +307 -0
  278. package/src/services/wxAppTelephonyUtils.ts +14 -0
  279. package/src/types.ts +238 -11
  280. package/src/utils/AGENTS.md +289 -0
  281. package/src/utils/PageCache.ts +38 -5
  282. package/src/utils/ai-docs/utils-spec.md +391 -0
  283. package/src/webex.js +2 -0
  284. package/test/unit/spec/cc.ts +1856 -122
  285. package/test/unit/spec/logger-proxy.ts +70 -0
  286. package/test/unit/spec/metrics/behavioral-events.ts +18 -0
  287. package/test/unit/spec/services/AddressBook.ts +37 -6
  288. package/test/unit/spec/services/AnswerCallOnWebexService.ts +223 -0
  289. package/test/unit/spec/services/ApiAiAssistant.ts +273 -0
  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 +7 -1
  294. package/test/unit/spec/services/WebexCrossClientService.ts +261 -0
  295. package/test/unit/spec/services/WxAppTelephonyMercurySync.ts +113 -0
  296. package/test/unit/spec/services/config/Util.ts +85 -0
  297. package/test/unit/spec/services/config/index.ts +85 -29
  298. package/test/unit/spec/services/core/Utils.ts +481 -2
  299. package/test/unit/spec/services/core/WebexRequest.ts +3 -1
  300. package/test/unit/spec/services/core/aqm-reqs.ts +113 -1
  301. package/test/unit/spec/services/core/websocket/WebSocketManager.ts +137 -41
  302. package/test/unit/spec/services/core/websocket/connection-service.ts +3 -1
  303. package/test/unit/spec/services/task/AutoWrapup.ts +63 -0
  304. package/test/unit/spec/services/task/Task.ts +677 -0
  305. package/test/unit/spec/services/task/TaskFactory.ts +99 -0
  306. package/test/unit/spec/services/task/TaskManager.ts +2209 -918
  307. package/test/unit/spec/services/task/TaskUtils.ts +235 -0
  308. package/test/unit/spec/services/task/WebexCallingUtils.ts +153 -0
  309. package/test/unit/spec/services/task/contact.ts +33 -0
  310. package/test/unit/spec/services/task/dialer.ts +372 -96
  311. package/test/unit/spec/services/task/digital/Digital.ts +105 -0
  312. package/test/unit/spec/services/task/state-machine/TaskStateMachine.ts +3433 -0
  313. package/test/unit/spec/services/task/state-machine/guards.ts +839 -0
  314. package/test/unit/spec/services/task/state-machine/types.ts +18 -0
  315. package/test/unit/spec/services/task/state-machine/uiControlsComputer.ts +3101 -0
  316. package/test/unit/spec/services/task/taskTestUtils.ts +87 -0
  317. package/test/unit/spec/services/task/voice/Voice.ts +1523 -0
  318. package/test/unit/spec/services/task/voice/WebRTC.ts +235 -0
  319. package/test/unit/spec/services/task/voice/wxAppVoiceMethods.ts +459 -0
  320. package/umd/contact-center.min.js +2 -2
  321. package/umd/contact-center.min.js.map +1 -1
  322. package/dist/services/task/index.js +0 -1525
  323. package/dist/services/task/index.js.map +0 -1
  324. package/src/services/task/index.ts +0 -1801
  325. package/test/unit/spec/services/task/index.ts +0 -2184
package/dist/cc.js CHANGED
@@ -19,12 +19,17 @@ 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"));
22
25
  var _types4 = require("./services/task/types");
23
26
  var _MetricsManager = _interopRequireDefault(require("./metrics/MetricsManager"));
24
27
  var _constants4 = require("./metrics/constants");
25
- var _EntryPoint = _interopRequireDefault(require("./services/EntryPoint"));
26
- var _AddressBook = _interopRequireDefault(require("./services/AddressBook"));
27
- var _Queue = _interopRequireDefault(require("./services/Queue"));
28
+ var _EntryPoint = require("./services/EntryPoint");
29
+ var _AddressBook = require("./services/AddressBook");
30
+ var _Queue = require("./services/Queue");
31
+ var _ApiAiAssistant = require("./services/ApiAiAssistant");
32
+ var _UserPreference = require("./services/UserPreference");
28
33
  function _interopRequireDefault(e) { return e && e.__esModule ? e : { default: e }; }
29
34
  /**
30
35
  * @module CCPlugin
@@ -84,6 +89,7 @@ function _interopRequireDefault(e) { return e && e.__esModule ? e : { default: e
84
89
  * - `task:established` - Task/call has been connected
85
90
  * - `task:ended` - Task/call has ended
86
91
  * - `task:error` - An error occurred during task handling
92
+ * - `task:campaignPreviewReservation` - Campaign preview contact offered to agent
87
93
  *
88
94
  * @public
89
95
  *
@@ -182,6 +188,29 @@ class ContactCenter extends _webexCore.WebexPlugin {
182
188
  * @private
183
189
  */
184
190
 
191
+ /**
192
+ * REST telephony for wxApp thick-client answer (WXCC-6026)
193
+ * @private
194
+ */
195
+
196
+ /**
197
+ * usersub cross-client state for Webex App toast suppression
198
+ * @private
199
+ */
200
+
201
+ /**
202
+ * Mercury telephony mute sync for wxApp thick-client answer
203
+ * @private
204
+ */
205
+
206
+ /** True when wxApp mute sync opened Mercury (Extension/DN-only profiles). */
207
+ wxAppMercuryConnectedByCc = false;
208
+
209
+ /** True when wxApp mute sync registered the Webex device. */
210
+ wxAppDeviceRegisteredByCc = false;
211
+ static WXAPP_FALSE_PUBLISH_RETRY_DELAY_MS = 30_000;
212
+ static WXAPP_FALSE_PUBLISH_MAX_RETRIES = 3;
213
+
185
214
  /**
186
215
  * Core service managers for Contact Center operations
187
216
  * Includes agent, connection, and configuration services
@@ -272,6 +301,42 @@ class ContactCenter extends _webexCore.WebexPlugin {
272
301
  * ```
273
302
  */
274
303
 
304
+ /**
305
+ * API instance for managing Webex Contact Center user preferences
306
+ * Provides functionality to get, create, update, and delete user preferences
307
+ * @type {UserPreference}
308
+ * @public
309
+ * @example
310
+ * ```typescript
311
+ * const cc = webex.cc;
312
+ * await cc.register();
313
+ * await cc.stationLogin({ teamId: 'team123', loginOption: 'BROWSER' });
314
+ *
315
+ * // Get user preferences for current user
316
+ * const preferences = await cc.userPreference.getUserPreference();
317
+ *
318
+ * // Create new user preferences
319
+ * const newPrefs = await cc.userPreference.createUserPreference({
320
+ * userId: 'user123',
321
+ * preferences: { e911Reminder: true }
322
+ * });
323
+ *
324
+ * // Update user preferences
325
+ * const updatedPrefs = await cc.userPreference.updateUserPreference('user123', {
326
+ * preferences: { e911Reminder: false }
327
+ * });
328
+ *
329
+ * // Delete user preferences
330
+ * await cc.userPreference.deleteUserPreference('user123');
331
+ * ```
332
+ */
333
+
334
+ /**
335
+ * API instance for AI Assistant operations such as transcript controls.
336
+ * @type {ApiAIAssistant}
337
+ * @public
338
+ */
339
+
275
340
  /**
276
341
  * Logger utility for Contact Center plugin
277
342
  * Provides consistent logging across the plugin
@@ -293,6 +358,7 @@ class ContactCenter extends _webexCore.WebexPlugin {
293
358
  this.$webex.once(_constants.READY, () => {
294
359
  // @ts-ignore
295
360
  this.$config = this.config;
361
+ this.validatePluginConfig();
296
362
 
297
363
  /**
298
364
  * This is used for handling the async requests by sending webex.request and wait for corresponding websocket event.
@@ -304,21 +370,24 @@ class ContactCenter extends _webexCore.WebexPlugin {
304
370
  webex: this.$webex,
305
371
  connectionConfig: this.getConnectionConfig()
306
372
  });
307
- this.services.webSocketManager.on('message', this.handleWebsocketMessage);
308
373
  this.webCallingService = new _WebCallingService.default(this.$webex);
374
+ this.answerCallOnWebexService = new _AnswerCallOnWebexService.default(this.$webex);
375
+ this.webexCrossClientService = new _WebexCrossClientService.default(this.$webex);
376
+ this.wxAppTelephonyMercurySync = new _WxAppTelephonyMercurySync.default(this.$webex);
377
+ this.apiAIAssistant = new _ApiAiAssistant.ApiAIAssistant(this.$webex);
309
378
  this.metricsManager = _MetricsManager.default.getInstance({
310
379
  webex: this.$webex
311
380
  });
312
- this.taskManager = _TaskManager.default.getTaskManager(this.services.contact, this.webCallingService, this.services.webSocketManager);
381
+ this.taskManager = _TaskManager.default.getTaskManager(this.apiAIAssistant, this.services.contact, this.webCallingService, this.services.webSocketManager, this.services.rtdWebSocketManager);
382
+ this.taskManager.setAnswerCallOnWebexService(this.answerCallOnWebexService);
313
383
  this.incomingTaskListener();
314
384
 
315
385
  // Initialize API instances
316
386
  // will have future function for indivdual fetch etc so better be in an object
317
- this.entryPoint = new _EntryPoint.default(this.$webex);
318
- this.addressBook = new _AddressBook.default(this.$webex, () => this.agentConfig?.addressBookId);
319
- this.queue = new _Queue.default(this.$webex);
320
-
321
- // Initialize logger
387
+ this.entryPoint = new _EntryPoint.EntryPoint(this.$webex);
388
+ this.addressBook = new _AddressBook.AddressBook(this.$webex, () => this.agentConfig?.addressBookId);
389
+ this.queue = new _Queue.Queue(this.$webex);
390
+ this.userPreference = new _UserPreference.UserPreference(this.$webex, () => this.agentConfig?.agentId);
322
391
  _loggerProxy.default.initialize(this.$webex.logger);
323
392
  });
324
393
  }
@@ -343,6 +412,16 @@ class ContactCenter extends _webexCore.WebexPlugin {
343
412
  this.trigger(_types4.TASK_EVENTS.TASK_HYDRATE, task);
344
413
  };
345
414
 
415
+ /**
416
+ * Handles multi-login hydrate events for SDK instances without Mobius registration
417
+ * @private
418
+ * @param {ITask} task The task object associated with the multi-login hydrate
419
+ */
420
+ handleTaskMultiLoginHydrate = task => {
421
+ // @ts-ignore
422
+ this.trigger(_types4.TASK_EVENTS.TASK_MULTI_LOGIN_HYDRATE, task);
423
+ };
424
+
346
425
  /**
347
426
  * Handles task merged events when tasks are combined eg: EPDN merge/transfer
348
427
  * @private
@@ -353,6 +432,19 @@ class ContactCenter extends _webexCore.WebexPlugin {
353
432
  this.trigger(_types4.TASK_EVENTS.TASK_MERGED, task);
354
433
  };
355
434
 
435
+ /**
436
+ * Handles campaign preview reservation events when a contact is offered to the agent
437
+ * @private
438
+ * @param {ITask} task The campaign reservation task
439
+ */
440
+ handleCampaignPreviewReservation = task => {
441
+ // @ts-ignore
442
+ this.trigger(_types4.TASK_EVENTS.TASK_CAMPAIGN_PREVIEW_RESERVATION, task);
443
+ };
444
+ handleRTDWebsocketMessage = event => {
445
+ this.taskManager.handleRealtimeWebsocketEvent(event);
446
+ };
447
+
356
448
  /**
357
449
  * Sets up event listeners for incoming tasks and task hydration
358
450
  * Subscribes to task events from the task manager
@@ -361,7 +453,9 @@ class ContactCenter extends _webexCore.WebexPlugin {
361
453
  incomingTaskListener() {
362
454
  this.taskManager.on(_types4.TASK_EVENTS.TASK_INCOMING, this.handleIncomingTask);
363
455
  this.taskManager.on(_types4.TASK_EVENTS.TASK_HYDRATE, this.handleTaskHydrate);
456
+ this.taskManager.on(_types4.TASK_EVENTS.TASK_MULTI_LOGIN_HYDRATE, this.handleTaskMultiLoginHydrate);
364
457
  this.taskManager.on(_types4.TASK_EVENTS.TASK_MERGED, this.handleTaskMerged);
458
+ this.taskManager.on(_types4.TASK_EVENTS.TASK_CAMPAIGN_PREVIEW_RESERVATION, this.handleCampaignPreviewReservation);
365
459
  }
366
460
 
367
461
  /**
@@ -401,13 +495,14 @@ class ContactCenter extends _webexCore.WebexPlugin {
401
495
  * ```
402
496
  */
403
497
  async register() {
404
- _loggerProxy.default.info('Starting CC SDK registration', {
498
+ _loggerProxy.default.log('Starting CC SDK registration', {
405
499
  module: _constants.CC_FILE,
406
500
  method: _constants.METHODS.REGISTER
407
501
  });
408
502
  try {
409
503
  this.metricsManager.timeEvent([_constants4.METRIC_EVENT_NAMES.WEBSOCKET_REGISTER_SUCCESS, _constants4.METRIC_EVENT_NAMES.WEBSOCKET_REGISTER_FAILED]);
410
504
  this.setupEventListeners();
505
+ this.services.webSocketManager.on('message', this.handleWebsocketMessage);
411
506
  const resp = await this.connectWebsocket();
412
507
  // Ensure 'dn' is always populated from 'defaultDn'
413
508
  resp.dn = resp.defaultDn;
@@ -470,9 +565,17 @@ class ContactCenter extends _webexCore.WebexPlugin {
470
565
  this.metricsManager.timeEvent([_constants4.METRIC_EVENT_NAMES.WEBSOCKET_DEREGISTER_SUCCESS, _constants4.METRIC_EVENT_NAMES.WEBSOCKET_DEREGISTER_FAIL]);
471
566
  this.taskManager.off(_types4.TASK_EVENTS.TASK_INCOMING, this.handleIncomingTask);
472
567
  this.taskManager.off(_types4.TASK_EVENTS.TASK_HYDRATE, this.handleTaskHydrate);
568
+ this.taskManager.off(_types4.TASK_EVENTS.TASK_MULTI_LOGIN_HYDRATE, this.handleTaskMultiLoginHydrate);
569
+ this.taskManager.off(_types4.TASK_EVENTS.TASK_CAMPAIGN_PREVIEW_RESERVATION, this.handleCampaignPreviewReservation);
473
570
  this.taskManager.unregisterIncomingCallEvent();
474
571
  this.services.webSocketManager.off('message', this.handleWebsocketMessage);
572
+ this.services.rtdWebSocketManager.off('message', this.handleRTDWebsocketMessage);
475
573
  this.services.connectionService.off('connectionLost', this.handleConnectionLost);
574
+ const {
575
+ publishError: wxAppPublishError
576
+ } = await this.teardownWxAppLocalState({
577
+ clearInitFlag: true
578
+ });
476
579
  if (this.agentConfig.webRtcEnabled && this.agentConfig.loginVoiceOptions.includes(_types.LoginOption.BROWSER)) {
477
580
  if (this.$webex.internal.mercury.connected) {
478
581
  this.$webex.internal.mercury.off('online');
@@ -489,9 +592,18 @@ class ContactCenter extends _webexCore.WebexPlugin {
489
592
  if (!this.services.webSocketManager.isSocketClosed) {
490
593
  this.services.webSocketManager.close(false, 'Unregistering the SDK');
491
594
  }
595
+ if (this.services.rtdWebSocketManager && !this.services.rtdWebSocketManager.isSocketClosed) {
596
+ this.services.rtdWebSocketManager.close(false, 'Unregistering the SDK');
597
+ }
598
+ if (this.services.rtdWebSocketManager && !this.services.rtdWebSocketManager.isSocketClosed) {
599
+ this.services.rtdWebSocketManager.close(false, 'Unregistering the RTD websocket');
600
+ }
492
601
 
493
602
  // Clear any cached agent configuration
494
603
  this.agentConfig = null;
604
+ if (wxAppPublishError) {
605
+ throw wxAppPublishError;
606
+ }
495
607
  _loggerProxy.default.log('Deregistered successfully', {
496
608
  module: _constants.CC_FILE,
497
609
  method: _constants.METHODS.DEREGISTER
@@ -545,6 +657,12 @@ class ContactCenter extends _webexCore.WebexPlugin {
545
657
  * ```
546
658
  */
547
659
  async getBuddyAgents(data) {
660
+ const {
661
+ action,
662
+ state,
663
+ mediaType = 'telephony'
664
+ } = data;
665
+ const buddyAgentState = state ?? (action === 'Transfer' ? _constants2.AGENT_STATE_AVAILABLE : undefined);
548
666
  _loggerProxy.default.info('Fetching buddy agents', {
549
667
  module: _constants.CC_FILE,
550
668
  method: _constants.METHODS.GET_BUDDY_AGENTS
@@ -554,13 +672,16 @@ class ContactCenter extends _webexCore.WebexPlugin {
554
672
  const resp = await this.services.agent.buddyAgents({
555
673
  data: {
556
674
  agentProfileId: this.agentConfig.agentProfileID,
557
- ...data
675
+ mediaType,
676
+ ...(buddyAgentState ? {
677
+ state: buddyAgentState
678
+ } : {})
558
679
  }
559
680
  });
560
681
  this.metricsManager.trackEvent(_constants4.METRIC_EVENT_NAMES.FETCH_BUDDY_AGENTS_SUCCESS, {
561
682
  ..._MetricsManager.default.getCommonTrackingFieldForAQMResponse(resp),
562
- mediaType: data.mediaType,
563
- buddyAgentState: data.state,
683
+ mediaType,
684
+ buddyAgentState,
564
685
  buddyAgentCount: resp.data.agentList.length
565
686
  }, ['operational']);
566
687
  _loggerProxy.default.log(`Successfully retrieved ${resp.data.agentList.length} buddy agents`, {
@@ -573,8 +694,8 @@ class ContactCenter extends _webexCore.WebexPlugin {
573
694
  const failureResp = error.details;
574
695
  this.metricsManager.trackEvent(_constants4.METRIC_EVENT_NAMES.FETCH_BUDDY_AGENTS_FAILED, {
575
696
  ..._MetricsManager.default.getCommonTrackingFieldForAQMResponseFailed(failureResp),
576
- mediaType: data.mediaType,
577
- buddyAgentState: data.state
697
+ mediaType,
698
+ buddyAgentState
578
699
  }, ['operational']);
579
700
  const {
580
701
  error: detailedError
@@ -590,13 +711,14 @@ class ContactCenter extends _webexCore.WebexPlugin {
590
711
  * @private
591
712
  */
592
713
  async connectWebsocket() {
593
- _loggerProxy.default.info('Connecting to websocket', {
714
+ _loggerProxy.default.log('Connecting to websocket', {
594
715
  module: _constants.CC_FILE,
595
716
  method: _constants.METHODS.CONNECT_WEBSOCKET
596
717
  });
597
718
  try {
598
719
  const data = await this.services.webSocketManager.initWebSocket({
599
- body: this.getConnectionConfig()
720
+ body: this.getConnectionConfig(),
721
+ resource: _constants3.SUBSCRIBE_API
600
722
  });
601
723
  const agentId = data.agentId;
602
724
  const orgId = this.$webex.credentials.getOrgId();
@@ -605,12 +727,53 @@ class ContactCenter extends _webexCore.WebexPlugin {
605
727
  module: _constants.CC_FILE,
606
728
  method: _constants.METHODS.CONNECT_WEBSOCKET
607
729
  });
608
-
730
+ const configFlags = {
731
+ isEndTaskEnabled: this.agentConfig.isEndTaskEnabled,
732
+ isEndConsultEnabled: this.agentConfig.isEndConsultEnabled,
733
+ webRtcEnabled: this.agentConfig.webRtcEnabled,
734
+ autoWrapup: this.agentConfig.wrapUpData?.wrapUpProps?.autoWrapup ?? false,
735
+ aiFeature: this.agentConfig.aiFeature,
736
+ consultTransfer: {
737
+ allowConsultToQueue: this.agentConfig.allowConsultToQueue,
738
+ accessQueue: this.agentConfig.accessQueue,
739
+ accessEntryPoint: this.agentConfig.accessEntryPoint,
740
+ accessBuddyTeam: this.agentConfig.accessBuddyTeam
741
+ },
742
+ enableWxBetterTogether: this.isWxBetterTogetherEnabled()
743
+ };
744
+ this.taskManager.setConfigFlags(configFlags);
609
745
  // TODO: Make profile a singleton to make it available throughout app/sdk so we dont need to inject info everywhere
610
746
  this.taskManager.setWrapupData(this.agentConfig.wrapUpData);
611
747
  this.taskManager.setAgentId(this.agentConfig.agentId);
612
748
  this.taskManager.setWebRtcEnabled(this.agentConfig.webRtcEnabled);
613
- if (this.agentConfig.webRtcEnabled && this.agentConfig.loginVoiceOptions.includes(_types.LoginOption.BROWSER)) {
749
+ this.apiAIAssistant.setAIFeatureFlags(this.agentConfig.aiFeature);
750
+
751
+ /**
752
+ * RTD websocket currently supports realtime transcripts and suggested responses.
753
+ * Extend this condition when additional AI RTD features are introduced.
754
+ */
755
+ if (this.agentConfig.aiFeature?.realtimeTranscripts?.enable || this.agentConfig.aiFeature?.suggestedResponses?.enable) {
756
+ _loggerProxy.default.info('Connecting to RTD websocket', {
757
+ module: _constants.CC_FILE,
758
+ method: _constants.METHODS.CONNECT_WEBSOCKET
759
+ });
760
+ this.services.rtdWebSocketManager.initWebSocket({
761
+ body: this.getConnectionConfig(),
762
+ resource: _constants3.RTD_SUBSCRIBE_API
763
+ }).then(() => {
764
+ _loggerProxy.default.log('RTD websocket connected successfully', {
765
+ module: _constants.CC_FILE,
766
+ method: _constants.METHODS.CONNECT_WEBSOCKET
767
+ });
768
+ this.services.rtdWebSocketManager.on('message', this.handleRTDWebsocketMessage);
769
+ }).catch(error => {
770
+ _loggerProxy.default.error(`Error connecting to RTD websocket ${error}`, {
771
+ module: _constants.CC_FILE,
772
+ method: _constants.METHODS.CONNECT_WEBSOCKET
773
+ });
774
+ });
775
+ }
776
+ if (this.agentConfig.webRtcEnabled && this.agentConfig.loginVoiceOptions.includes(_types.LoginOption.BROWSER) && !this.isWebRTCRegistrationDisabled()) {
614
777
  try {
615
778
  await this.$webex.internal.mercury.connect();
616
779
  _loggerProxy.default.log('Authentication: webex.internal.mercury.connect successful', {
@@ -623,9 +786,19 @@ class ContactCenter extends _webexCore.WebexPlugin {
623
786
  method: _constants.METHODS.CONNECT_WEBSOCKET
624
787
  });
625
788
  }
789
+ } else if (this.isWebRTCRegistrationDisabled()) {
790
+ _loggerProxy.default.info('Skipping Mobius registration because disableWebRTCRegistration is enabled', {
791
+ module: _constants.CC_FILE,
792
+ method: _constants.METHODS.CONNECT_WEBSOCKET
793
+ });
626
794
  }
627
795
  if (this.$config && this.$config.allowAutomatedRelogin) {
628
796
  await this.silentRelogin();
797
+ } else {
798
+ _loggerProxy.default.log('Skipping silent relogin: allowAutomatedRelogin is disabled', {
799
+ module: _constants.CC_FILE,
800
+ method: _constants.METHODS.CONNECT_WEBSOCKET
801
+ });
629
802
  }
630
803
  return this.agentConfig;
631
804
  } catch (error) {
@@ -666,21 +839,27 @@ class ContactCenter extends _webexCore.WebexPlugin {
666
839
  * ```
667
840
  */
668
841
  async stationLogin(data) {
669
- _loggerProxy.default.info('Starting agent station login', {
842
+ const loggerContext = {
670
843
  module: _constants.CC_FILE,
671
844
  method: _constants.METHODS.STATION_LOGIN
672
- });
845
+ };
673
846
  try {
847
+ _loggerProxy.default.log(`Starting agent station login | loginOption: ${data?.loginOption} teamId: ${data?.teamId}`, loggerContext);
674
848
  this.metricsManager.timeEvent([_constants4.METRIC_EVENT_NAMES.STATION_LOGIN_SUCCESS, _constants4.METRIC_EVENT_NAMES.STATION_LOGIN_FAILED]);
675
- if (data.loginOption === _types.LoginOption.AGENT_DN && !(0, _Utils.isValidDialNumber)(data.dialNumber)) {
676
- const error = new Error('INVALID_DIAL_NUMBER');
677
- // @ts-ignore - adding custom key to the error object
678
- error.details = {
679
- data: {
680
- reason: 'INVALID_DIAL_NUMBER'
681
- }
682
- };
683
- throw error;
849
+ const dialPlanEntries = this.agentConfig?.dialPlan?.dialPlanEntity ?? [];
850
+ if (data.loginOption === _types.LoginOption.AGENT_DN) {
851
+ _loggerProxy.default.log(`Validating dial number | dialPlanEnabled: ${!!this.agentConfig?.dialPlan} | dialPlanEntryCount: ${dialPlanEntries.length}`, loggerContext);
852
+ if (!(0, _Utils.isValidDialNumber)(data.dialNumber, dialPlanEntries)) {
853
+ _loggerProxy.default.log(`Dial number validation failed | dialNumber: ${data.dialNumber} | dialPlanEntryCount: ${dialPlanEntries.length}`, loggerContext);
854
+ const error = new Error('INVALID_DIAL_NUMBER');
855
+ // @ts-ignore - adding custom key to the error object
856
+ error.details = {
857
+ data: {
858
+ reason: 'INVALID_DIAL_NUMBER'
859
+ }
860
+ };
861
+ throw error;
862
+ }
684
863
  }
685
864
  const loginResponse = await this.services.agent.stationLogin({
686
865
  data: {
@@ -696,8 +875,13 @@ class ContactCenter extends _webexCore.WebexPlugin {
696
875
  auxCodeId: _constants.EMPTY_STRING
697
876
  }
698
877
  });
699
- if (this.agentConfig.webRtcEnabled && data.loginOption === _types.LoginOption.BROWSER) {
878
+ if (this.agentConfig.webRtcEnabled && data.loginOption === _types.LoginOption.BROWSER && !this.isWebRTCRegistrationDisabled()) {
700
879
  await this.webCallingService.registerWebCallingLine();
880
+ } else if (this.agentConfig.webRtcEnabled && data.loginOption === _types.LoginOption.BROWSER && this.isWebRTCRegistrationDisabled()) {
881
+ _loggerProxy.default.info('Skipping web calling line registration because disableWebRTCRegistration is enabled', {
882
+ module: _constants.CC_FILE,
883
+ method: _constants.METHODS.STATION_LOGIN
884
+ });
701
885
  }
702
886
  const resp = await loginResponse;
703
887
  const {
@@ -716,6 +900,13 @@ class ContactCenter extends _webexCore.WebexPlugin {
716
900
  notifsTrackingId: resp.trackingId
717
901
  };
718
902
  this.webCallingService.setLoginOption(data.loginOption);
903
+ if (this.agentConfig) {
904
+ this.agentConfig.deviceType = data.loginOption;
905
+ if (data.loginOption === _types.LoginOption.AGENT_DN || data.loginOption === _types.LoginOption.EXTENSION) {
906
+ this.agentConfig.defaultDn = data.dialNumber;
907
+ this.agentConfig.dn = data.dialNumber;
908
+ }
909
+ }
719
910
  this.metricsManager.trackEvent(_constants4.METRIC_EVENT_NAMES.STATION_LOGIN_SUCCESS, {
720
911
  ..._MetricsManager.default.getCommonTrackingFieldForAQMResponse(resp),
721
912
  loginType: data.loginOption,
@@ -728,6 +919,7 @@ class ContactCenter extends _webexCore.WebexPlugin {
728
919
  method: _constants.METHODS.STATION_LOGIN,
729
920
  trackingId: resp.trackingId
730
921
  });
922
+ await this.ensureWxAppPostStationLogin();
731
923
  return response;
732
924
  } catch (error) {
733
925
  const failure = error.details;
@@ -782,6 +974,7 @@ class ContactCenter extends _webexCore.WebexPlugin {
782
974
  if (this.webCallingService) {
783
975
  this.webCallingService.deregisterWebCallingLine();
784
976
  }
977
+ await this.teardownWxAppLocalState();
785
978
  _loggerProxy.default.log(`Agent station logout completed successfully`, {
786
979
  module: _constants.CC_FILE,
787
980
  method: _constants.METHODS.STATION_LOGOUT,
@@ -1021,6 +1214,391 @@ class ContactCenter extends _webexCore.WebexPlugin {
1021
1214
  }
1022
1215
  };
1023
1216
 
1217
+ /**
1218
+ * Checks whether Mobius/WebRTC registration should be skipped by config
1219
+ * @returns {boolean} True when browser WebRTC registration is disabled
1220
+ * @private
1221
+ */
1222
+ isWebRTCRegistrationDisabled() {
1223
+ return this.$config?.disableWebRTCRegistration === true;
1224
+ }
1225
+
1226
+ /**
1227
+ * Validates contact-center plugin configuration before service initialization
1228
+ * @private
1229
+ */
1230
+ validatePluginConfig() {
1231
+ if (this.$config?.disableWebRTCRegistration === true && this.$config?.allowMultiLogin === false) {
1232
+ 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.');
1233
+ }
1234
+ }
1235
+
1236
+ /**
1237
+ * Whether wxApp thick-client answer is enabled for this SDK instance.
1238
+ * @public
1239
+ */
1240
+ isWxBetterTogetherEnabled() {
1241
+ return this.$config?.enableWxBetterTogether === true;
1242
+ }
1243
+
1244
+ /**
1245
+ * Current station login option (Extension, Dial Number, or Browser/Desktop).
1246
+ * Prefer webCallingService — updated on every stationLogin before wxApp hooks run.
1247
+ * @private
1248
+ */
1249
+ getCurrentStationLoginOption() {
1250
+ return this.webCallingService?.loginOption ?? this.agentConfig?.deviceType;
1251
+ }
1252
+
1253
+ /**
1254
+ * wxApp thick-client answer is supported for Extension and Dial Number station login only —
1255
+ * not Browser/Desktop (WebRTC) login.
1256
+ * @private
1257
+ */
1258
+ assertWxAppStationLoginSupportedForEnable() {
1259
+ const loginOption = this.getCurrentStationLoginOption();
1260
+ if (loginOption !== _types.LoginOption.EXTENSION && loginOption !== _types.LoginOption.AGENT_DN) {
1261
+ throw new Error('setManageWebexCallingInWxcc requires EXTENSION or AGENT_DN station login. Complete station login before enabling.');
1262
+ }
1263
+ }
1264
+
1265
+ /**
1266
+ * Clears runtime wxApp config after logout/deregister so stale flags do not apply on relogin.
1267
+ * @private
1268
+ */
1269
+ resetEnableWxBetterTogetherConfig() {
1270
+ if (this.$config) {
1271
+ this.$config.enableWxBetterTogether = false;
1272
+ }
1273
+ this.taskManager.applyEnableWxBetterTogether(false);
1274
+ }
1275
+
1276
+ /**
1277
+ * Runtime enable/disable for wxApp Better Together (toast suppression + Mercury mute sync).
1278
+ *
1279
+ * **Phase 1 (WXCC-6026 / MMT): NOT part of the public host contract.**
1280
+ * Hosts must set `webexConfig.cc.enableWxBetterTogether` before `webex.init()` / `cc.register()`.
1281
+ * To change the flag after the SDK is initialized, re-init the SDK with the updated config.
1282
+ *
1283
+ * **Supported public read API:** {@link isWxBetterTogetherEnabled}.
1284
+ * **Supported telephony API:** unified `task.accept()`, `task.decline()`, `task.toggleMute()`,
1285
+ * `task.transmitDtmf()` — SDK routes wxApp calls internally when the init flag is active.
1286
+ *
1287
+ * **Production lifecycle does not call this method.** Station login, silent relogin, logout,
1288
+ * and deregister use {@link ensureWxAppPostStationLogin} and {@link teardownWxAppLocalState}
1289
+ * (usersub publish + Mercury subscribe/unsubscribe based on the init flag).
1290
+ *
1291
+ * This setter remains as a **private implementation** for Phase 2 runtime toggle and unit tests.
1292
+ * It updates `$config.enableWxBetterTogether`, TaskManager flags, cross-client usersub
1293
+ * (`answer-calls-on-wxcc`), and Mercury mute sync; rolls back config on publish/connect failure.
1294
+ *
1295
+ * @param enabled - `true` to enable wxApp answer + usersub suppression; `false` to disable and tear down.
1296
+ * @throws When enabling without login, on unsupported BROWSER station login, or when usersub/Mercury init fails.
1297
+ * @internal
1298
+ * @see enableWxBetterTogether (CCPluginConfig init flag)
1299
+ * @see ensureWxAppPostStationLogin
1300
+ * @see teardownWxAppLocalState
1301
+ */
1302
+ async setManageWebexCallingInWxcc(enabled) {
1303
+ if (enabled && !this.$webex.internal.device?.userId) {
1304
+ throw new Error('Cannot publish answer-calls-on-wxcc: user is not logged in');
1305
+ }
1306
+ if (enabled) {
1307
+ this.assertWxAppStationLoginSupportedForEnable();
1308
+ }
1309
+ const previousEnabled = this.isWxBetterTogetherEnabled();
1310
+ if (this.$config) {
1311
+ this.$config.enableWxBetterTogether = enabled;
1312
+ }
1313
+ this.taskManager.applyEnableWxBetterTogether(enabled);
1314
+ let publishedEnable = false;
1315
+ try {
1316
+ if (enabled) {
1317
+ await this.ensureWxAppMercuryAndSubscribe();
1318
+ await this.publishAnswerOnWebexCrossClientState(true);
1319
+ publishedEnable = true;
1320
+ this.taskManager.syncWxAppMuteFromCallDetailsForAllTasks();
1321
+ } else {
1322
+ await this.publishAnswerOnWebexCrossClientState(false);
1323
+ this.wxAppTelephonyMercurySync.unsubscribe();
1324
+ await this.releaseWxAppMercuryResources();
1325
+ }
1326
+ } catch (error) {
1327
+ if (publishedEnable) {
1328
+ await this.revertWxAppCrossClientPublish();
1329
+ } else if (enabled) {
1330
+ this.wxAppTelephonyMercurySync.unsubscribe();
1331
+ await this.releaseWxAppMercuryResources();
1332
+ }
1333
+ if (this.$config) {
1334
+ this.$config.enableWxBetterTogether = previousEnabled;
1335
+ }
1336
+ this.taskManager.applyEnableWxBetterTogether(previousEnabled);
1337
+ throw error;
1338
+ }
1339
+ }
1340
+ async ensureWxAppPostStationLogin() {
1341
+ if (this.getCurrentStationLoginOption() === _types.LoginOption.BROWSER) {
1342
+ return;
1343
+ }
1344
+ let publishedEnable = false;
1345
+ try {
1346
+ if (this.isWxBetterTogetherEnabled()) {
1347
+ await this.ensureWxAppMercuryAndSubscribe();
1348
+ await this.publishAnswerOnWebexCrossClientState(true);
1349
+ publishedEnable = true;
1350
+ this.taskManager.syncWxAppMuteFromCallDetailsForAllTasks();
1351
+ } else {
1352
+ await this.ensureWxAppDeviceRegistered();
1353
+ await this.publishAnswerOnWebexCrossClientState(false, {
1354
+ force: true
1355
+ });
1356
+ this.webexCrossClientService.teardown();
1357
+ this.wxAppTelephonyMercurySync.unsubscribe();
1358
+ await this.releaseWxAppMercuryResources();
1359
+ }
1360
+ } catch (error) {
1361
+ _loggerProxy.default.error(`Failed to initialize wxApp post-station-login: ${error}`, {
1362
+ module: _constants.CC_FILE,
1363
+ method: _constants.METHODS.STATION_LOGIN
1364
+ });
1365
+ if (this.isWxBetterTogetherEnabled()) {
1366
+ if (publishedEnable) {
1367
+ await this.revertWxAppCrossClientPublish();
1368
+ } else {
1369
+ this.wxAppTelephonyMercurySync.unsubscribe();
1370
+ await this.releaseWxAppMercuryResources();
1371
+ }
1372
+ this.resetEnableWxBetterTogetherConfig();
1373
+ } else {
1374
+ this.scheduleForcedFalsePublishRetry();
1375
+ }
1376
+ }
1377
+ }
1378
+ clearWxAppFalsePublishRetryTimer() {
1379
+ if (this.wxAppFalsePublishRetryTimer) {
1380
+ clearTimeout(this.wxAppFalsePublishRetryTimer);
1381
+ this.wxAppFalsePublishRetryTimer = undefined;
1382
+ }
1383
+ }
1384
+ scheduleForcedFalsePublishRetry(retryAttempt = 0) {
1385
+ this.scheduleFalsePublishRetry(retryAttempt, {
1386
+ requireDisabled: true
1387
+ });
1388
+ }
1389
+
1390
+ /**
1391
+ * Retries compensating false publish after rollback failure, regardless of enabled flag.
1392
+ * @private
1393
+ */
1394
+ scheduleCompensatingFalsePublishRetry(retryAttempt = 0) {
1395
+ this.scheduleFalsePublishRetry(retryAttempt);
1396
+ }
1397
+ scheduleFalsePublishRetry(retryAttempt = 0, options = {}) {
1398
+ if (retryAttempt >= ContactCenter.WXAPP_FALSE_PUBLISH_MAX_RETRIES) {
1399
+ return;
1400
+ }
1401
+ if (options?.requireDisabled && this.isWxBetterTogetherEnabled()) {
1402
+ return;
1403
+ }
1404
+ this.clearWxAppFalsePublishRetryTimer();
1405
+ this.wxAppFalsePublishRetryTimer = setTimeout(async () => {
1406
+ this.wxAppFalsePublishRetryTimer = undefined;
1407
+ if (options?.requireDisabled && this.isWxBetterTogetherEnabled()) {
1408
+ return;
1409
+ }
1410
+ if (!options?.requireDisabled && this.isWxBetterTogetherEnabled() && this.webexCrossClientService.isAnswerCallsStateActive()) {
1411
+ return;
1412
+ }
1413
+ try {
1414
+ await this.ensureWxAppDeviceRegistered();
1415
+ await this.publishAnswerOnWebexCrossClientState(false, {
1416
+ force: true
1417
+ });
1418
+ this.webexCrossClientService.teardown();
1419
+ this.wxAppTelephonyMercurySync.unsubscribe();
1420
+ await this.releaseWxAppMercuryResources();
1421
+ } catch (retryError) {
1422
+ _loggerProxy.default.error(`Failed to retry forced answer-calls-on-wxcc false publish: ${retryError}`, {
1423
+ module: _constants.CC_FILE,
1424
+ method: _constants.METHODS.SET_MANAGE_WEBEX_CALLING_IN_WXCC
1425
+ });
1426
+ this.scheduleFalsePublishRetry(retryAttempt + 1, options);
1427
+ }
1428
+ }, ContactCenter.WXAPP_FALSE_PUBLISH_RETRY_DELAY_MS);
1429
+ }
1430
+
1431
+ /**
1432
+ * Best-effort rollback when usersub true was published but wxApp setup did not complete.
1433
+ * @private
1434
+ */
1435
+ async revertWxAppCrossClientPublish() {
1436
+ try {
1437
+ await this.publishAnswerOnWebexCrossClientState(false, {
1438
+ force: true
1439
+ });
1440
+ } catch (error) {
1441
+ _loggerProxy.default.error(`Failed to publish compensating answer-calls-on-wxcc false during wxApp rollback: ${error}`, {
1442
+ module: _constants.CC_FILE,
1443
+ method: _constants.METHODS.SET_MANAGE_WEBEX_CALLING_IN_WXCC
1444
+ });
1445
+ this.scheduleCompensatingFalsePublishRetry();
1446
+ }
1447
+ this.webexCrossClientService.teardown();
1448
+ this.wxAppTelephonyMercurySync.unsubscribe();
1449
+ await this.releaseWxAppMercuryResources();
1450
+ }
1451
+ async ensureWxAppDeviceRegistered() {
1452
+ const device = this.$webex.internal.device;
1453
+ if (device && !device.registered && device.register) {
1454
+ await device.register();
1455
+ this.wxAppDeviceRegisteredByCc = true;
1456
+ _loggerProxy.default.log('WxApp: device registered for cross-client publish', {
1457
+ module: _constants.CC_FILE,
1458
+ method: _constants.METHODS.ENSURE_WXAPP_MERCURY_CONNECTED
1459
+ });
1460
+ }
1461
+ }
1462
+ async ensureWxAppMercuryConnected() {
1463
+ const mercury = this.$webex.internal.mercury;
1464
+ await this.ensureWxAppDeviceRegistered();
1465
+ if (mercury && !mercury.connected) {
1466
+ await mercury.connect();
1467
+ this.wxAppMercuryConnectedByCc = true;
1468
+ _loggerProxy.default.log('WxApp mute sync: mercury connected', {
1469
+ module: _constants.CC_FILE,
1470
+ method: _constants.METHODS.ENSURE_WXAPP_MERCURY_CONNECTED
1471
+ });
1472
+ }
1473
+ }
1474
+
1475
+ /**
1476
+ * Disconnects Mercury and unregisters the device when wxApp mute sync opened them.
1477
+ * @private
1478
+ */
1479
+ async releaseWxAppMercuryResources() {
1480
+ const mercury = this.$webex.internal.mercury;
1481
+ const device = this.$webex.internal.device;
1482
+ if (this.wxAppMercuryConnectedByCc && mercury?.connected) {
1483
+ try {
1484
+ await mercury.disconnect();
1485
+ this.wxAppMercuryConnectedByCc = false;
1486
+ _loggerProxy.default.log('WxApp mute sync: mercury disconnected', {
1487
+ module: _constants.CC_FILE,
1488
+ method: _constants.METHODS.ENSURE_WXAPP_MERCURY_CONNECTED
1489
+ });
1490
+ } catch (error) {
1491
+ _loggerProxy.default.error(`Failed to disconnect wxApp Mercury: ${error}`, {
1492
+ module: _constants.CC_FILE,
1493
+ method: _constants.METHODS.ENSURE_WXAPP_MERCURY_CONNECTED
1494
+ });
1495
+ }
1496
+ }
1497
+ if (this.wxAppDeviceRegisteredByCc && device?.registered && device.unregister) {
1498
+ try {
1499
+ // @ts-ignore
1500
+ await device.unregister();
1501
+ this.wxAppDeviceRegisteredByCc = false;
1502
+ _loggerProxy.default.log('WxApp mute sync: device unregistered', {
1503
+ module: _constants.CC_FILE,
1504
+ method: _constants.METHODS.ENSURE_WXAPP_MERCURY_CONNECTED
1505
+ });
1506
+ } catch (error) {
1507
+ _loggerProxy.default.error(`Failed to unregister wxApp device: ${error}`, {
1508
+ module: _constants.CC_FILE,
1509
+ method: _constants.METHODS.ENSURE_WXAPP_MERCURY_CONNECTED
1510
+ });
1511
+ }
1512
+ } else if (this.wxAppDeviceRegisteredByCc) {
1513
+ this.wxAppDeviceRegisteredByCc = false;
1514
+ }
1515
+ }
1516
+
1517
+ /**
1518
+ * Clears wxApp runtime state and feature-owned resources. Publish failures are logged;
1519
+ * optional rethrow for deregister when callers need to surface usersub errors.
1520
+ * @private
1521
+ */
1522
+ async teardownWxAppLocalState(options) {
1523
+ this.clearWxAppFalsePublishRetryTimer();
1524
+ let publishError;
1525
+ try {
1526
+ const shouldForceFalsePublish = this.isWxBetterTogetherEnabled() || this.webexCrossClientService.isAnswerCallsStateActive();
1527
+ await this.publishAnswerOnWebexCrossClientState(false, {
1528
+ force: shouldForceFalsePublish
1529
+ });
1530
+ } catch (error) {
1531
+ publishError = error;
1532
+ _loggerProxy.default.error(`Failed to publish answer-calls-on-wxcc false during wxApp teardown: ${error}`, {
1533
+ module: _constants.CC_FILE,
1534
+ method: _constants.METHODS.SET_MANAGE_WEBEX_CALLING_IN_WXCC
1535
+ });
1536
+ }
1537
+ this.webexCrossClientService.teardown();
1538
+ this.wxAppTelephonyMercurySync.unsubscribe();
1539
+ await this.releaseWxAppMercuryResources();
1540
+ if (options?.clearInitFlag) {
1541
+ this.resetEnableWxBetterTogetherConfig();
1542
+ }
1543
+ if (publishError) {
1544
+ this.scheduleCompensatingFalsePublishRetry();
1545
+ }
1546
+ if (options?.rethrowPublishError && publishError) {
1547
+ throw publishError;
1548
+ }
1549
+ return {
1550
+ publishError: publishError ?? undefined
1551
+ };
1552
+ }
1553
+ async ensureWxAppMercuryAndSubscribe() {
1554
+ if (!this.isWxBetterTogetherEnabled()) {
1555
+ return;
1556
+ }
1557
+ if (this.getCurrentStationLoginOption() === _types.LoginOption.BROWSER) {
1558
+ return;
1559
+ }
1560
+ const agentId = this.agentConfig?.agentId;
1561
+ if (!agentId) {
1562
+ _loggerProxy.default.error('Cannot subscribe wxApp mute sync: agentId unavailable', {
1563
+ module: _constants.CC_FILE,
1564
+ method: _constants.METHODS.SYNC_WXAPP_MUTE_FROM_MERCURY
1565
+ });
1566
+ return;
1567
+ }
1568
+ try {
1569
+ await this.ensureWxAppMercuryConnected();
1570
+ this.wxAppTelephonyMercurySync.subscribe(agentId, (callId, muted) => {
1571
+ this.taskManager.applyWxAppMuteStateFromSync(callId, muted);
1572
+ });
1573
+ } catch (error) {
1574
+ _loggerProxy.default.error(`Failed to ensure wxApp Mercury mute sync: ${error}`, {
1575
+ module: _constants.CC_FILE,
1576
+ method: _constants.METHODS.SYNC_WXAPP_MUTE_FROM_MERCURY
1577
+ });
1578
+ this.wxAppTelephonyMercurySync.unsubscribe();
1579
+ await this.releaseWxAppMercuryResources();
1580
+ throw error;
1581
+ }
1582
+ }
1583
+ async publishAnswerOnWebexCrossClientState(enable, options) {
1584
+ if (enable && !this.isWxBetterTogetherEnabled()) {
1585
+ return;
1586
+ }
1587
+ if (!enable && !options?.force && !this.webexCrossClientService.isAnswerCallsStateActive()) {
1588
+ return;
1589
+ }
1590
+ const userId = this.$webex.internal.device?.userId;
1591
+ if (!userId) {
1592
+ return;
1593
+ }
1594
+ await this.webexCrossClientService.setManageWebexCallingInWxcc(enable, {
1595
+ userId
1596
+ });
1597
+ if (enable) {
1598
+ this.clearWxAppFalsePublishRetryTimer();
1599
+ }
1600
+ }
1601
+
1024
1602
  /**
1025
1603
  * Initializes event listeners for the Contact Center service
1026
1604
  * Sets up handlers for connection state changes and other core events
@@ -1052,13 +1630,13 @@ class ContactCenter extends _webexCore.WebexPlugin {
1052
1630
  async handleConnectionLost(msg) {
1053
1631
  if (msg.isConnectionLost) {
1054
1632
  // TODO: Emit an event saying connection is lost
1055
- _loggerProxy.default.info('event=handleConnectionLost | Connection lost', {
1633
+ _loggerProxy.default.log('event=handleConnectionLost | Connection lost', {
1056
1634
  module: _constants.CC_FILE,
1057
1635
  method: _constants.METHODS.HANDLE_CONNECTION_LOST
1058
1636
  });
1059
1637
  } else if (msg.isSocketReconnected) {
1060
1638
  // TODO: Emit an event saying connection is re-estabilished
1061
- _loggerProxy.default.info('event=handleConnectionReconnect | Connection reconnected attempting to request silent relogin', {
1639
+ _loggerProxy.default.log('event=handleConnectionReconnect | Connection reconnected attempting to request silent relogin', {
1062
1640
  module: _constants.CC_FILE,
1063
1641
  method: _constants.METHODS.HANDLE_CONNECTION_LOST
1064
1642
  });
@@ -1073,7 +1651,7 @@ class ContactCenter extends _webexCore.WebexPlugin {
1073
1651
  * @private
1074
1652
  */
1075
1653
  async silentRelogin() {
1076
- _loggerProxy.default.info('Starting silent relogin process', {
1654
+ _loggerProxy.default.log('Starting silent relogin process', {
1077
1655
  module: _constants.CC_FILE,
1078
1656
  method: _constants.METHODS.SILENT_RELOGIN
1079
1657
  });
@@ -1095,7 +1673,7 @@ class ContactCenter extends _webexCore.WebexPlugin {
1095
1673
  this.agentConfig.currentTeamId = reLoginResponse.data.teamId;
1096
1674
  await this.handleDeviceType(deviceType, dn);
1097
1675
  if (lastStateChangeReason === 'agent-wss-disconnect') {
1098
- _loggerProxy.default.info('event=requestAutoStateChange | Requesting state change to available on socket reconnect', {
1676
+ _loggerProxy.default.log('event=requestAutoStateChange | Requesting state change to available on socket reconnect', {
1099
1677
  module: _constants.CC_FILE,
1100
1678
  method: _constants.METHODS.SILENT_RELOGIN
1101
1679
  });
@@ -1119,8 +1697,7 @@ class ContactCenter extends _webexCore.WebexPlugin {
1119
1697
  }
1120
1698
  this.agentConfig.lastStateAuxCodeId = auxCodeId;
1121
1699
  this.agentConfig.isAgentLoggedIn = true;
1122
- // TODO: https://jira-eng-gpk2.cisco.com/jira/browse/SPARK-626777 Implement the de-register method and close the listener there
1123
- this.services.webSocketManager.on('message', this.handleWebsocketMessage);
1700
+ await this.ensureWxAppPostStationLogin();
1124
1701
  _loggerProxy.default.log(`Silent relogin process completed successfully with login Option: ${reLoginResponse.data.deviceType} teamId: ${reLoginResponse.data.teamId}`, {
1125
1702
  module: _constants.CC_FILE,
1126
1703
  method: _constants.METHODS.SILENT_RELOGIN,
@@ -1155,6 +1732,13 @@ class ContactCenter extends _webexCore.WebexPlugin {
1155
1732
  this.agentConfig.deviceType = deviceType;
1156
1733
  switch (deviceType) {
1157
1734
  case _types.LoginOption.BROWSER:
1735
+ if (this.isWebRTCRegistrationDisabled()) {
1736
+ _loggerProxy.default.info('Skipping web calling line registration because disableWebRTCRegistration is enabled', {
1737
+ module: _constants.CC_FILE,
1738
+ method: _constants.METHODS.HANDLE_DEVICE_TYPE
1739
+ });
1740
+ break;
1741
+ }
1158
1742
  try {
1159
1743
  await this.webCallingService.registerWebCallingLine();
1160
1744
  } catch (error) {
@@ -1336,6 +1920,196 @@ class ContactCenter extends _webexCore.WebexPlugin {
1336
1920
  }
1337
1921
  }
1338
1922
 
1923
+ /**
1924
+ * Accepts a campaign preview contact, initiating the outbound call.
1925
+ *
1926
+ * When a campaign manager reserves a contact for an agent, the agent receives an
1927
+ * `AgentOfferCampaignReservation` event. The agent can then accept the preview contact
1928
+ * to initiate the outbound call.
1929
+ *
1930
+ * @param {PreviewContactPayload} payload - The preview contact payload containing interactionId and campaignId (campaign name, not UUID).
1931
+ * @returns {Promise<TaskResponse>} Promise resolving with agent contact on success.
1932
+ * @throws {Error} If the operation fails (network error, customer unavailable, etc.)
1933
+ *
1934
+ * @example
1935
+ * ```typescript
1936
+ * webex.cc.on('task:campaignPreviewReservation', async (task) => {
1937
+ * const { interactionId } = task.data;
1938
+ * // campaignId is the campaign name (e.g. "MyCampaign"), not a UUID
1939
+ * const campaignId = task.data.interaction.callProcessingDetails.campaignId;
1940
+ *
1941
+ * const result = await webex.cc.acceptPreviewContact({ interactionId, campaignId });
1942
+ * });
1943
+ * ```
1944
+ */
1945
+ async acceptPreviewContact(payload) {
1946
+ _loggerProxy.default.info('Accepting campaign preview contact', {
1947
+ module: _constants.CC_FILE,
1948
+ method: _constants.METHODS.ACCEPT_PREVIEW_CONTACT
1949
+ });
1950
+ try {
1951
+ this.metricsManager.timeEvent([_constants4.METRIC_EVENT_NAMES.CAMPAIGN_PREVIEW_ACCEPT_SUCCESS, _constants4.METRIC_EVENT_NAMES.CAMPAIGN_PREVIEW_ACCEPT_FAILED]);
1952
+ const result = await this.services.dialer.acceptPreviewContact({
1953
+ data: payload
1954
+ });
1955
+ this.metricsManager.trackEvent(_constants4.METRIC_EVENT_NAMES.CAMPAIGN_PREVIEW_ACCEPT_SUCCESS, {
1956
+ ..._MetricsManager.default.getCommonTrackingFieldForAQMResponse(result),
1957
+ interactionId: payload.interactionId,
1958
+ campaignId: payload.campaignId
1959
+ }, ['behavioral', 'business', 'operational']);
1960
+ _loggerProxy.default.log('Campaign preview contact accepted successfully', {
1961
+ module: _constants.CC_FILE,
1962
+ method: _constants.METHODS.ACCEPT_PREVIEW_CONTACT,
1963
+ trackingId: result.trackingId,
1964
+ interactionId: payload.interactionId
1965
+ });
1966
+ return result;
1967
+ } catch (error) {
1968
+ const failure = error.details;
1969
+ this.metricsManager.trackEvent(_constants4.METRIC_EVENT_NAMES.CAMPAIGN_PREVIEW_ACCEPT_FAILED, {
1970
+ ..._MetricsManager.default.getCommonTrackingFieldForAQMResponseFailed(failure),
1971
+ interactionId: payload.interactionId,
1972
+ campaignId: payload.campaignId
1973
+ }, ['behavioral', 'business', 'operational']);
1974
+ const {
1975
+ error: detailedError
1976
+ } = (0, _Utils.getErrorDetails)(error, _constants.METHODS.ACCEPT_PREVIEW_CONTACT, _constants.CC_FILE);
1977
+ throw detailedError;
1978
+ }
1979
+ }
1980
+
1981
+ /**
1982
+ * Skips a campaign preview contact, requesting the next contact from the campaign.
1983
+ *
1984
+ * When a campaign manager reserves a contact for an agent, the agent receives an
1985
+ * `AgentOfferCampaignReservation` event. Instead of accepting, the agent can skip the
1986
+ * preview contact to move to the next contact in the campaign.
1987
+ *
1988
+ * @param {PreviewContactPayload} payload - The preview contact payload containing interactionId and campaignId (campaign name, not UUID).
1989
+ * @returns {Promise<TaskResponse>} Promise resolving with agent contact on success.
1990
+ * @throws {Error} If the operation fails (network error, etc.)
1991
+ *
1992
+ * @example
1993
+ * ```typescript
1994
+ * webex.cc.on('task:campaignPreviewReservation', async (task) => {
1995
+ * const { interactionId } = task.data;
1996
+ * const campaignId = task.data.interaction.callProcessingDetails.campaignId;
1997
+ *
1998
+ * const result = await webex.cc.skipPreviewContact({ interactionId, campaignId });
1999
+ * });
2000
+ * ```
2001
+ */
2002
+ async skipPreviewContact(payload) {
2003
+ const task = this.taskManager.getTask(payload.interactionId);
2004
+ if (task?.data?.interaction?.callProcessingDetails?.campaignPreviewSkipDisabled === 'true') {
2005
+ _loggerProxy.default.warn('Skip action is disabled for this campaign preview contact', {
2006
+ module: _constants.CC_FILE,
2007
+ method: _constants.METHODS.SKIP_PREVIEW_CONTACT,
2008
+ interactionId: payload.interactionId
2009
+ });
2010
+ throw new Error('Skip action is disabled for this campaign preview contact');
2011
+ }
2012
+ _loggerProxy.default.info('Skipping campaign preview contact', {
2013
+ module: _constants.CC_FILE,
2014
+ method: _constants.METHODS.SKIP_PREVIEW_CONTACT
2015
+ });
2016
+ try {
2017
+ this.metricsManager.timeEvent([_constants4.METRIC_EVENT_NAMES.CAMPAIGN_PREVIEW_SKIP_SUCCESS, _constants4.METRIC_EVENT_NAMES.CAMPAIGN_PREVIEW_SKIP_FAILED]);
2018
+ const result = await this.services.dialer.skipPreviewContact({
2019
+ data: payload
2020
+ });
2021
+ this.metricsManager.trackEvent(_constants4.METRIC_EVENT_NAMES.CAMPAIGN_PREVIEW_SKIP_SUCCESS, {
2022
+ ..._MetricsManager.default.getCommonTrackingFieldForAQMResponse(result),
2023
+ interactionId: payload.interactionId,
2024
+ campaignId: payload.campaignId
2025
+ }, ['behavioral', 'business', 'operational']);
2026
+ _loggerProxy.default.log('Campaign preview contact skipped successfully', {
2027
+ module: _constants.CC_FILE,
2028
+ method: _constants.METHODS.SKIP_PREVIEW_CONTACT,
2029
+ trackingId: result.trackingId,
2030
+ interactionId: payload.interactionId
2031
+ });
2032
+ return result;
2033
+ } catch (error) {
2034
+ const failure = error.details;
2035
+ this.metricsManager.trackEvent(_constants4.METRIC_EVENT_NAMES.CAMPAIGN_PREVIEW_SKIP_FAILED, {
2036
+ ..._MetricsManager.default.getCommonTrackingFieldForAQMResponseFailed(failure),
2037
+ interactionId: payload.interactionId,
2038
+ campaignId: payload.campaignId
2039
+ }, ['behavioral', 'business', 'operational']);
2040
+ const {
2041
+ error: detailedError
2042
+ } = (0, _Utils.getErrorDetails)(error, _constants.METHODS.SKIP_PREVIEW_CONTACT, _constants.CC_FILE);
2043
+ throw detailedError;
2044
+ }
2045
+ }
2046
+
2047
+ /**
2048
+ * Removes a campaign preview contact from the campaign list entirely.
2049
+ *
2050
+ * When a campaign manager reserves a contact for an agent, the agent receives an
2051
+ * `AgentOfferCampaignReservation` event. Instead of accepting or skipping, the agent can
2052
+ * remove the preview contact to permanently take it out of the campaign contact list.
2053
+ *
2054
+ * @param {PreviewContactPayload} payload - The preview contact payload containing interactionId and campaignId (campaign name, not UUID).
2055
+ * @returns {Promise<TaskResponse>} Promise resolving with agent contact on success.
2056
+ * @throws {Error} If the operation fails (network error, etc.)
2057
+ *
2058
+ * @example
2059
+ * ```typescript
2060
+ * webex.cc.on('task:campaignPreviewReservation', async (task) => {
2061
+ * const { interactionId } = task.data;
2062
+ * const campaignId = task.data.interaction.callProcessingDetails.campaignId;
2063
+ *
2064
+ * const result = await webex.cc.removePreviewContact({ interactionId, campaignId });
2065
+ * });
2066
+ * ```
2067
+ */
2068
+ async removePreviewContact(payload) {
2069
+ const task = this.taskManager.getTask(payload.interactionId);
2070
+ if (task?.data?.interaction?.callProcessingDetails?.campaignPreviewRemoveDisabled === 'true') {
2071
+ _loggerProxy.default.warn('Remove action is disabled for this campaign preview contact', {
2072
+ module: _constants.CC_FILE,
2073
+ method: _constants.METHODS.REMOVE_PREVIEW_CONTACT,
2074
+ interactionId: payload.interactionId
2075
+ });
2076
+ throw new Error('Remove action is disabled for this campaign preview contact');
2077
+ }
2078
+ _loggerProxy.default.info('Removing campaign preview contact', {
2079
+ module: _constants.CC_FILE,
2080
+ method: _constants.METHODS.REMOVE_PREVIEW_CONTACT
2081
+ });
2082
+ try {
2083
+ this.metricsManager.timeEvent([_constants4.METRIC_EVENT_NAMES.CAMPAIGN_PREVIEW_REMOVE_SUCCESS, _constants4.METRIC_EVENT_NAMES.CAMPAIGN_PREVIEW_REMOVE_FAILED]);
2084
+ const result = await this.services.dialer.removePreviewContact({
2085
+ data: payload
2086
+ });
2087
+ this.metricsManager.trackEvent(_constants4.METRIC_EVENT_NAMES.CAMPAIGN_PREVIEW_REMOVE_SUCCESS, {
2088
+ ..._MetricsManager.default.getCommonTrackingFieldForAQMResponse(result),
2089
+ interactionId: payload.interactionId,
2090
+ campaignId: payload.campaignId
2091
+ }, ['behavioral', 'business', 'operational']);
2092
+ _loggerProxy.default.log('Campaign preview contact removed successfully', {
2093
+ module: _constants.CC_FILE,
2094
+ method: _constants.METHODS.REMOVE_PREVIEW_CONTACT,
2095
+ trackingId: result.trackingId,
2096
+ interactionId: payload.interactionId
2097
+ });
2098
+ return result;
2099
+ } catch (error) {
2100
+ const failure = error.details;
2101
+ this.metricsManager.trackEvent(_constants4.METRIC_EVENT_NAMES.CAMPAIGN_PREVIEW_REMOVE_FAILED, {
2102
+ ..._MetricsManager.default.getCommonTrackingFieldForAQMResponseFailed(failure),
2103
+ interactionId: payload.interactionId,
2104
+ campaignId: payload.campaignId
2105
+ }, ['behavioral', 'business', 'operational']);
2106
+ const {
2107
+ error: detailedError
2108
+ } = (0, _Utils.getErrorDetails)(error, _constants.METHODS.REMOVE_PREVIEW_CONTACT, _constants.CC_FILE);
2109
+ throw detailedError;
2110
+ }
2111
+ }
2112
+
1339
2113
  /**
1340
2114
  * Fetches outdial ANI (Automatic Number Identification) entries for an outdial ANI ID.
1341
2115
  *
@@ -1467,6 +2241,7 @@ class ContactCenter extends _webexCore.WebexPlugin {
1467
2241
  /**
1468
2242
  * Updates the agent device type and login configuration.
1469
2243
  * Use this method to change how an agent connects to the contact center system (e.g., switching from browser-based calling to a desk phone extension).
2244
+ * Change to any field of the profile is allowed;
1470
2245
  *
1471
2246
  * @param {AgentDeviceUpdate} data Configuration containing:
1472
2247
  * - loginOption: New device type ('BROWSER', 'EXTENSION', 'AGENT_DN')
@@ -1500,24 +2275,8 @@ class ContactCenter extends _webexCore.WebexPlugin {
1500
2275
  trackingId
1501
2276
  });
1502
2277
  try {
1503
- // Only block if both loginOption AND teamId remain unchanged
1504
- if (this.webCallingService?.loginOption === data.loginOption && data.teamId === this.agentConfig.currentTeamId) {
1505
- const message = 'Will not proceed with device update as new Device type is same as current device type and teamId is same as current teamId';
1506
- const err = new Error(message);
1507
- err.details = {
1508
- type: 'Identical Device Change Failure',
1509
- orgId: this.$webex.credentials.getOrgId(),
1510
- trackingId,
1511
- data: {
1512
- agentId: this.agentConfig.agentId,
1513
- reasonCode: 'R002',
1514
- reason: message
1515
- }
1516
- };
1517
- throw err;
1518
- }
1519
2278
  await this.stationLogout({
1520
- logoutReason: 'User requested agent device change'
2279
+ logoutReason: 'User requested agent profile update'
1521
2280
  });
1522
2281
  const loginPayload = {
1523
2282
  teamId: data.teamId,
@@ -1555,8 +2314,8 @@ class ContactCenter extends _webexCore.WebexPlugin {
1555
2314
  }
1556
2315
 
1557
2316
  /**
1558
- * Returns paginated entry points for the organization.
1559
- * Thin wrapper around internal EntryPoint instance.
2317
+ * Returns paginated entry points using the EntryPoint service defaults.
2318
+ * Existing request parameters can override those defaults.
1560
2319
  * @public
1561
2320
  */
1562
2321
  async getEntryPoints(params = {}) {
@@ -1564,8 +2323,8 @@ class ContactCenter extends _webexCore.WebexPlugin {
1564
2323
  }
1565
2324
 
1566
2325
  /**
1567
- * Returns paginated contact service queues for the organization.
1568
- * Thin wrapper around internal Queue instance.
2326
+ * Returns paginated contact service queues using the Queue service defaults.
2327
+ * Existing request parameters can override those defaults.
1569
2328
  * @public
1570
2329
  */
1571
2330
  async getQueues(params = {}) {