@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
@@ -0,0 +1,1380 @@
1
+ "use strict";
2
+
3
+ Object.defineProperty(exports, "__esModule", {
4
+ value: true
5
+ });
6
+ exports.default = void 0;
7
+ var _constants = require("../../../constants");
8
+ var _Utils = require("../../core/Utils");
9
+ var _types = require("../types");
10
+ var _Task = _interopRequireDefault(require("../Task"));
11
+ var _loggerProxy = _interopRequireDefault(require("../../../logger-proxy"));
12
+ var _MetricsManager = _interopRequireDefault(require("../../../metrics/MetricsManager"));
13
+ var _constants2 = require("../../../metrics/constants");
14
+ var _stateMachine = require("../state-machine");
15
+ var _TaskUtils = require("../TaskUtils");
16
+ var _wxAppTelephonyUtils = require("../../wxAppTelephonyUtils");
17
+ var _wxAppVoiceMethods = require("./wxAppVoiceMethods");
18
+ function _interopRequireDefault(e) { return e && e.__esModule ? e : { default: e }; }
19
+ class Voice extends _Task.default {
20
+ static WXAPP_MUTE_SYNC_RETRY_DELAY_MS = 50;
21
+ static WXAPP_MUTE_SYNC_MAX_RETRIES = 3;
22
+ enableWxBetterTogether = false;
23
+ wxAppMuted = false;
24
+ wxAppAnswerPending = false;
25
+ wxAppAcceptInFlight = false;
26
+ constructor(contact, data, callOptions, wrapupData, agentId) {
27
+ const resolvedOptions = {
28
+ isEndTaskEnabled: callOptions?.isEndTaskEnabled ?? true,
29
+ isEndConsultEnabled: callOptions?.isEndConsultEnabled ?? true,
30
+ voiceVariant: callOptions?.voiceVariant ?? _types.VOICE_VARIANT.PSTN,
31
+ isRecordingEnabled: callOptions?.isRecordingEnabled ?? true,
32
+ enableWxBetterTogether: callOptions?.enableWxBetterTogether ?? false
33
+ };
34
+ super(contact, data, {
35
+ ...resolvedOptions,
36
+ consultTransferConfig: callOptions?.consultTransferConfig
37
+ }, wrapupData, agentId);
38
+ this.enableWxBetterTogether = resolvedOptions.enableWxBetterTogether;
39
+ this.answerCallOnWebexService = callOptions?.answerCallOnWebexService;
40
+ }
41
+ getWxAppVoiceDependencies() {
42
+ return {
43
+ enableWxBetterTogether: this.enableWxBetterTogether,
44
+ answerCallOnWebexService: this.answerCallOnWebexService,
45
+ agentId: this.agentId,
46
+ getTaskData: () => this.data,
47
+ getTaskState: () => this.stateMachineService?.getSnapshot?.()?.value,
48
+ getWxAppMuted: () => this.wxAppMuted,
49
+ setWxAppMuted: muted => {
50
+ this.wxAppMuted = muted;
51
+ }
52
+ };
53
+ }
54
+
55
+ /** @deprecated Use {@link Voice.getWxAppVoiceDependencies} */
56
+ getWxAppVoiceDeps() {
57
+ return this.getWxAppVoiceDependencies();
58
+ }
59
+ isWebexAppCallingOffer() {
60
+ return (0, _wxAppVoiceMethods.isWebexAppCallingOffer)(this.getWxAppVoiceDeps());
61
+ }
62
+ isWebexAppInboundCallingOffer() {
63
+ return (0, _wxAppVoiceMethods.isWebexAppInboundCallingOffer)(this.getWxAppVoiceDeps());
64
+ }
65
+ setWxAppAnswerPending(pending) {
66
+ this.wxAppAnswerPending = pending;
67
+ this.uiControlConfig = {
68
+ ...this.uiControlConfig,
69
+ wxAppAnswerPending: pending
70
+ };
71
+ this.updateUiControls(true);
72
+ }
73
+ setWxAppAcceptInFlight(inFlight) {
74
+ this.wxAppAcceptInFlight = inFlight;
75
+ this.uiControlConfig = {
76
+ ...this.uiControlConfig,
77
+ wxAppAcceptInFlight: inFlight
78
+ };
79
+ this.updateUiControls(true);
80
+ }
81
+ setEnableWxBetterTogether(enabled) {
82
+ this.enableWxBetterTogether = enabled;
83
+ this.uiControlConfig = {
84
+ ...this.uiControlConfig,
85
+ enableWxBetterTogether: enabled
86
+ };
87
+ this.updateUiControls(true);
88
+ }
89
+ applyWxAppMuteStateFromSync(incomingCallId, muted) {
90
+ if (!this.enableWxBetterTogether) {
91
+ return;
92
+ }
93
+ const activeCallId = this.getWebexCallingCallId();
94
+ if (!activeCallId || !incomingCallId.endsWith(activeCallId) || this.wxAppMuted === muted) {
95
+ return;
96
+ }
97
+ this.wxAppMuted = muted;
98
+ this.emit(_types.TASK_EVENTS.TASK_WXAPP_MUTE_STATE_UPDATED, {
99
+ muted
100
+ });
101
+ }
102
+ getWxAppMuted() {
103
+ return this.wxAppMuted;
104
+ }
105
+ static delay(ms) {
106
+ return new Promise(resolve => {
107
+ setTimeout(resolve, ms);
108
+ });
109
+ }
110
+ canRetryWxAppMuteSync() {
111
+ if (!this.enableWxBetterTogether) {
112
+ return false;
113
+ }
114
+ return Boolean((0, _wxAppVoiceMethods.getCallingDeviceDetails)(this.getWxAppVoiceDeps())?.deviceCallId) && !this.getWebexCallingCallId();
115
+ }
116
+ shouldSkipWxAppMuteSync() {
117
+ if (this.data?.interaction?.isTerminated) {
118
+ return true;
119
+ }
120
+ return this.isWebexAppCallingOffer() && !this.uiControlConfig?.wxAppAnswerPending;
121
+ }
122
+ applyWxAppMuteFromBackfill(callId, muted) {
123
+ if (!this.enableWxBetterTogether || this.wxAppMuted === muted) {
124
+ return;
125
+ }
126
+ const activeCallId = this.getWebexCallingCallId();
127
+ if (activeCallId && !callId.endsWith(activeCallId) && !activeCallId.endsWith(callId)) {
128
+ return;
129
+ }
130
+ this.wxAppMuted = muted;
131
+ this.emit(_types.TASK_EVENTS.TASK_WXAPP_MUTE_STATE_UPDATED, {
132
+ muted
133
+ });
134
+ }
135
+ async syncWxAppMuteFromCallDetails(retryAttempt = 0) {
136
+ if (!this.enableWxBetterTogether || !this.answerCallOnWebexService) {
137
+ return undefined;
138
+ }
139
+ if (retryAttempt === 0 && this.shouldSkipWxAppMuteSync()) {
140
+ return undefined;
141
+ }
142
+ if (retryAttempt === 0 && this.wxAppMuteSyncInFlight) {
143
+ return this.wxAppMuteSyncInFlight;
144
+ }
145
+ const syncPromise = this.performWxAppMuteSync(retryAttempt);
146
+ if (retryAttempt === 0) {
147
+ this.wxAppMuteSyncInFlight = syncPromise;
148
+ syncPromise.finally(() => {
149
+ if (this.wxAppMuteSyncInFlight === syncPromise) {
150
+ this.wxAppMuteSyncInFlight = undefined;
151
+ }
152
+ }).catch(() => undefined);
153
+ return syncPromise;
154
+ }
155
+ return syncPromise;
156
+ }
157
+ async performWxAppMuteSync(retryAttempt) {
158
+ if (this.shouldSkipWxAppMuteSync()) {
159
+ return undefined;
160
+ }
161
+ let callId = this.getWebexCallingCallId();
162
+ if (!callId) {
163
+ if (retryAttempt < Voice.WXAPP_MUTE_SYNC_MAX_RETRIES && this.canRetryWxAppMuteSync()) {
164
+ await Voice.delay(Voice.WXAPP_MUTE_SYNC_RETRY_DELAY_MS);
165
+ return this.performWxAppMuteSync(retryAttempt + 1);
166
+ }
167
+ callId = (0, _wxAppVoiceMethods.getCallingDeviceDetails)(this.getWxAppVoiceDeps())?.deviceCallId ?? null;
168
+ if (!callId) {
169
+ return undefined;
170
+ }
171
+ }
172
+ try {
173
+ const lineOwnerId = (0, _wxAppVoiceMethods.resolveWxAppLineOwnerId)(this.getWxAppVoiceDeps());
174
+ const details = await this.answerCallOnWebexService.getCallDetails({
175
+ callId,
176
+ lineOwnerId
177
+ });
178
+ if (details.muted !== undefined) {
179
+ this.applyWxAppMuteStateFromSync(callId, details.muted);
180
+ if (this.wxAppMuted !== details.muted) {
181
+ this.applyWxAppMuteFromBackfill(callId, details.muted);
182
+ }
183
+ return details.muted;
184
+ }
185
+ return this.wxAppMuted;
186
+ } catch (error) {
187
+ if (!(0, _wxAppTelephonyUtils.isWxAppCallNotFoundError)(error)) {
188
+ _loggerProxy.default.error(`Failed to sync wxApp mute from call details: ${error}`, {
189
+ module: _constants.CC_FILE,
190
+ method: _constants.METHODS.GET_CALL_DETAILS_ON_WEBEX,
191
+ interactionId: this.data?.interactionId
192
+ });
193
+ }
194
+ return undefined;
195
+ }
196
+ }
197
+ onTaskAssigned() {
198
+ this.setWxAppAnswerPending(false);
199
+ queueMicrotask(() => {
200
+ this.syncWxAppMuteFromCallDetails().catch(() => undefined);
201
+ });
202
+ }
203
+ onTaskHydrated() {
204
+ const state = this.stateMachineService?.getSnapshot?.()?.value;
205
+ const answerStillPending = state === _stateMachine.TaskState.OFFERED && (this.uiControlConfig?.wxAppAcceptInFlight || this.uiControlConfig?.wxAppAnswerPending);
206
+ if (!answerStillPending) {
207
+ this.setWxAppAnswerPending(false);
208
+ }
209
+ this.syncWxAppMuteFromCallDetails().catch(() => undefined);
210
+ }
211
+ getCallingDeviceDetails() {
212
+ return (0, _wxAppVoiceMethods.getCallingDeviceDetails)(this.getWxAppVoiceDeps());
213
+ }
214
+ getWebexCallingCallId() {
215
+ return (0, _wxAppVoiceMethods.getWebexCallingCallId)(this.getWxAppVoiceDeps());
216
+ }
217
+ createWxAppLifecycle() {
218
+ return {
219
+ setWxAppAcceptInFlight: inFlight => this.setWxAppAcceptInFlight(inFlight),
220
+ setWxAppAnswerPending: pending => this.setWxAppAnswerPending(pending),
221
+ resetWxAppMuted: () => {
222
+ this.wxAppMuted = false;
223
+ },
224
+ syncWxAppMuteFromCallDetails: () => this.syncWxAppMuteFromCallDetails(),
225
+ mapWxAppVoiceError: (error, method) => (0, _wxAppVoiceMethods.mapWxAppVoiceError)(error, method, _constants.CC_FILE)
226
+ };
227
+ }
228
+ getStateMachineSnapshot() {
229
+ return this.stateMachineService?.getSnapshot?.();
230
+ }
231
+
232
+ /**
233
+ * Accepts the task. Routes to wxApp telephony answer when `enableWxBetterTogether` and wxApp offer.
234
+ */
235
+ async accept() {
236
+ if (this.enableWxBetterTogether && this.isWebexAppCallingOffer()) {
237
+ await (0, _wxAppVoiceMethods.runWxAppAccept)(this.getWxAppVoiceDependencies(), this.createWxAppLifecycle());
238
+ return Promise.resolve();
239
+ }
240
+ return super.unsupportedMethodError(_constants.METHODS.ACCEPT);
241
+ }
242
+
243
+ /**
244
+ * Declines the task. Routes wxApp inbound to telephony reject; wxApp outdial offer to cancelTask.
245
+ */
246
+ async decline() {
247
+ if (this.enableWxBetterTogether && this.isWebexAppInboundCallingOffer()) {
248
+ await (0, _wxAppVoiceMethods.runWxAppReject)(this.getWxAppVoiceDependencies(), this.createWxAppLifecycle());
249
+ return Promise.resolve();
250
+ }
251
+ const isOutdial = this.data?.interaction?.outboundType === 'OUTDIAL';
252
+ if (!this.enableWxBetterTogether || !isOutdial || !this.isWebexAppCallingOffer()) {
253
+ return super.unsupportedMethodError(_constants.METHODS.REJECT);
254
+ }
255
+ const interactionId = this.data.interactionId;
256
+ _loggerProxy.default.log(`Declining wxApp outdial task for taskId:${interactionId}`, {
257
+ module: _constants.CC_FILE,
258
+ method: _constants.METHODS.REJECT,
259
+ interactionId
260
+ });
261
+ try {
262
+ this.metricsManager.timeEvent([_constants2.METRIC_EVENT_NAMES.TASK_DECLINE_SUCCESS, _constants2.METRIC_EVENT_NAMES.TASK_DECLINE_FAILED]);
263
+ this.setWxAppAnswerPending(false);
264
+ const response = await this.contact.cancelTask({
265
+ interactionId
266
+ });
267
+ this.metricsManager.trackEvent(_constants2.METRIC_EVENT_NAMES.TASK_DECLINE_SUCCESS, {
268
+ taskId: interactionId,
269
+ ..._MetricsManager.default.getCommonTrackingFieldForAQMResponse(response)
270
+ }, ['operational', 'behavioral']);
271
+ return response;
272
+ } catch (error) {
273
+ this.metricsManager.trackEvent(_constants2.METRIC_EVENT_NAMES.TASK_DECLINE_FAILED, {
274
+ taskId: interactionId,
275
+ error: error.toString(),
276
+ ..._MetricsManager.default.getCommonTrackingFieldForAQMResponseFailed(error.details || {})
277
+ }, ['operational', 'behavioral']);
278
+ const {
279
+ error: detailedError
280
+ } = (0, _Utils.getErrorDetails)(error, _constants.METHODS.REJECT, _constants.CC_FILE);
281
+ throw detailedError;
282
+ }
283
+ }
284
+
285
+ /**
286
+ * Toggles mute for wxApp engaged telephony when `enableWxBetterTogether` is active.
287
+ */
288
+ async toggleMute(options) {
289
+ if (this.enableWxBetterTogether && this.getWebexCallingCallId()) {
290
+ if (this.wxAppMuteToggleInFlight) {
291
+ await this.wxAppMuteToggleInFlight.catch(() => undefined);
292
+ }
293
+ const togglePromise = (0, _wxAppVoiceMethods.runWxAppToggleMute)(this.getWxAppVoiceDependencies(), this.createWxAppLifecycle(), options);
294
+ this.wxAppMuteToggleInFlight = togglePromise;
295
+ togglePromise.finally(() => {
296
+ if (this.wxAppMuteToggleInFlight === togglePromise) {
297
+ this.wxAppMuteToggleInFlight = undefined;
298
+ }
299
+ }).catch(() => undefined);
300
+ await togglePromise;
301
+ return;
302
+ }
303
+ super.unsupportedMethodError(_constants.METHODS.TOGGLE_MUTE);
304
+ }
305
+
306
+ /**
307
+ * Sends in-call DTMF for wxApp engaged telephony when `enableWxBetterTogether` is active.
308
+ */
309
+ async transmitDtmf(options) {
310
+ if (this.enableWxBetterTogether && this.getWebexCallingCallId()) {
311
+ await (0, _wxAppVoiceMethods.runWxAppTransmitDtmf)(this.getWxAppVoiceDependencies(), this.createWxAppLifecycle(), options);
312
+ return;
313
+ }
314
+ super.unsupportedMethodError(_constants.METHODS.TRANSMIT_DTMF);
315
+ }
316
+
317
+ /**
318
+ * This is used to hold the task.
319
+ * @returns Promise<TaskResponse>
320
+ * @throws Error
321
+ * @example
322
+ * ```typescript
323
+ * task.hold().then(()=>{}).catch(()=>{})
324
+ * ```
325
+ * */
326
+ async hold() {
327
+ return this.holdResume();
328
+ }
329
+
330
+ /**
331
+ * This is used to resume the task.
332
+ * @returns Promise<TaskResponse>
333
+ * @throws Error
334
+ * @example
335
+ * ```typescript
336
+ * task.resume().then(()=>{}).catch(()=>{})
337
+ * ```
338
+ * */
339
+ async resume() {
340
+ return this.holdResume();
341
+ }
342
+
343
+ /**
344
+ * This is used to hold or resume the task.
345
+ * @param isHeld: boolean - true to hold the task, false to resume it
346
+ * @returns Promise<TaskResponse>
347
+ * @throws Error
348
+ * @example
349
+ * ```typescript
350
+ * task.holdResume(isHeld: true).then(()=>{}).catch(()=>{})
351
+ * ```
352
+ * */
353
+ async holdResume() {
354
+ /*
355
+ Determine if the task is being held or resumed based on the media resource state
356
+ If the media resource is not found, default to resuming the task
357
+ */
358
+ const snapshot = this.getStateMachineSnapshot();
359
+ const snapshotState = snapshot?.value;
360
+ const mainInteractionId = this.data.interaction?.mainInteractionId || this.data.interactionId;
361
+ const mainMediaResource = this.data.interaction?.media?.[mainInteractionId]?.mediaResourceId || this.data.mediaResourceId;
362
+ const mediaHoldState = this.data.interaction?.media?.[mainInteractionId]?.isHold ?? this.data.interaction.media?.[mainMediaResource]?.isHold;
363
+ let shouldHold = !(mediaHoldState ?? false);
364
+ if (snapshotState === _stateMachine.TaskState.HELD || snapshotState === _stateMachine.TaskState.RESUME_INITIATING) {
365
+ shouldHold = false;
366
+ } else if (snapshotState === _stateMachine.TaskState.CONNECTED && mediaHoldState !== true) {
367
+ // CONNECTED with isHold:true can happen after consult RONA/decline when event ordering
368
+ // leaves the machine in CONNECTED while main media is still on hold — resume on first click.
369
+ shouldHold = true;
370
+ }
371
+
372
+ // Validate operation is allowed in current state
373
+ const state = snapshot;
374
+ if (state) {
375
+ const currentState = state.value;
376
+ if (shouldHold) {
377
+ if (!state.matches(_stateMachine.TaskState.CONNECTED)) {
378
+ const error = new Error(`Cannot hold call in current state: ${currentState}`);
379
+ _loggerProxy.default.error('Hold operation not allowed', {
380
+ module: _constants.CC_FILE,
381
+ method: _constants.METHODS.HOLD_RESUME,
382
+ interactionId: this.data.interactionId
383
+ });
384
+ throw error;
385
+ }
386
+ } else if (!state.matches(_stateMachine.TaskState.HELD) && !(state.matches(_stateMachine.TaskState.CONFERENCING) && mediaHoldState === true) && !(state.matches(_stateMachine.TaskState.CONNECTED) && mediaHoldState === true)) {
387
+ const error = new Error(`Cannot resume call in current state: ${currentState}`);
388
+ _loggerProxy.default.error('Resume operation not allowed', {
389
+ module: _constants.CC_FILE,
390
+ method: _constants.METHODS.HOLD_RESUME,
391
+ interactionId: this.data.interactionId
392
+ });
393
+ throw error;
394
+ }
395
+ }
396
+
397
+ // Send initiating event to transition to intermediate state
398
+ if (this.stateMachineService) {
399
+ const initiatingEvent = shouldHold ? _stateMachine.TaskEvent.HOLD_INITIATED : _stateMachine.TaskEvent.UNHOLD_INITIATED;
400
+ this.stateMachineService.send({
401
+ type: initiatingEvent,
402
+ mediaResourceId: mainMediaResource
403
+ });
404
+ }
405
+ _loggerProxy.default.info(`${shouldHold ? 'Holding' : 'Resuming'} task`, {
406
+ module: _constants.CC_FILE,
407
+ method: _constants.METHODS.HOLD_RESUME,
408
+ interactionId: this.data.interactionId
409
+ });
410
+ const [successEvt, failedEvt] = shouldHold ? [_constants2.METRIC_EVENT_NAMES.TASK_HOLD_SUCCESS, _constants2.METRIC_EVENT_NAMES.TASK_HOLD_FAILED] : [_constants2.METRIC_EVENT_NAMES.TASK_RESUME_SUCCESS, _constants2.METRIC_EVENT_NAMES.TASK_RESUME_FAILED];
411
+ this.metricsManager.timeEvent([successEvt, failedEvt]);
412
+ try {
413
+ let response;
414
+ if (shouldHold) {
415
+ response = await this.contact.hold({
416
+ interactionId: this.data.interactionId,
417
+ data: {
418
+ mediaResourceId: mainMediaResource
419
+ }
420
+ });
421
+
422
+ // Send success event to complete the transition
423
+ if (this.stateMachineService) {
424
+ this.stateMachineService.send({
425
+ type: _stateMachine.TaskEvent.HOLD_SUCCESS,
426
+ mediaResourceId: mainMediaResource
427
+ });
428
+ }
429
+ this.metricsManager.trackEvent(successEvt, {
430
+ taskId: this.data.interactionId,
431
+ mediaResourceId: mainMediaResource,
432
+ ..._MetricsManager.default.getCommonTrackingFieldForAQMResponse(response)
433
+ }, ['operational', 'behavioral']);
434
+ _loggerProxy.default.log(`Task placed on hold successfully`, {
435
+ module: _constants.CC_FILE,
436
+ method: _constants.METHODS.HOLD_RESUME,
437
+ trackingId: response.trackingId,
438
+ interactionId: this.data.interactionId
439
+ });
440
+ } else {
441
+ response = await this.contact.unHold({
442
+ interactionId: this.data.interactionId,
443
+ data: {
444
+ mediaResourceId: mainMediaResource
445
+ }
446
+ });
447
+
448
+ // Send success event to complete the transition
449
+ if (this.stateMachineService) {
450
+ this.stateMachineService.send({
451
+ type: _stateMachine.TaskEvent.UNHOLD_SUCCESS,
452
+ mediaResourceId: mainMediaResource
453
+ });
454
+ }
455
+ this.metricsManager.trackEvent(successEvt, {
456
+ taskId: this.data.interactionId,
457
+ mainInteractionId,
458
+ mediaResourceId: mainMediaResource,
459
+ ..._MetricsManager.default.getCommonTrackingFieldForAQMResponse(response)
460
+ }, ['operational', 'behavioral']);
461
+ _loggerProxy.default.log(`Task resumed successfully`, {
462
+ module: _constants.CC_FILE,
463
+ method: _constants.METHODS.HOLD_RESUME,
464
+ trackingId: response.trackingId,
465
+ interactionId: this.data.interactionId
466
+ });
467
+ }
468
+ return response;
469
+ } catch (error) {
470
+ const failureEvent = shouldHold ? _stateMachine.TaskEvent.HOLD_FAILED : _stateMachine.TaskEvent.UNHOLD_FAILED;
471
+ this.stateMachineService.send({
472
+ type: failureEvent,
473
+ reason: error.toString(),
474
+ mediaResourceId: this.data.mediaResourceId
475
+ });
476
+ const {
477
+ error: detailedError
478
+ } = (0, _Utils.getErrorDetails)(error, 'holdResume', _constants.CC_FILE);
479
+ this.metricsManager.trackEvent(failedEvt, shouldHold ? {
480
+ taskId: this.data.interactionId,
481
+ mediaResourceId: this.data.mediaResourceId,
482
+ error: error.toString(),
483
+ ..._MetricsManager.default.getCommonTrackingFieldForAQMResponseFailed(error.details || {})
484
+ } : {
485
+ taskId: this.data.interactionId,
486
+ error: error.toString(),
487
+ ..._MetricsManager.default.getCommonTrackingFieldForAQMResponseFailed(error.details || {})
488
+ }, ['operational', 'behavioral']);
489
+ throw detailedError;
490
+ }
491
+ }
492
+
493
+ /**
494
+ * This is used to pause the call recording
495
+ * @returns Promise<TaskResponse>
496
+ * @throws Error
497
+ * @example
498
+ * ```typescript
499
+ * task.pauseRecording().then(()=>{}).catch(()=>{});
500
+ * ```
501
+ */
502
+ async pauseRecording() {
503
+ // Validate recording is active
504
+ const state = this.getStateMachineSnapshot();
505
+ if (state) {
506
+ const {
507
+ recordingControlsAvailable,
508
+ recordingInProgress
509
+ } = state.context;
510
+ const recordingActive = Boolean(recordingControlsAvailable && recordingInProgress);
511
+ if (!recordingActive) {
512
+ const error = new Error('Recording is not active or already paused');
513
+ _loggerProxy.default.error('Pause recording operation not allowed', {
514
+ module: _constants.CC_FILE,
515
+ method: 'pauseRecording',
516
+ interactionId: this.data.interactionId
517
+ });
518
+ throw error;
519
+ }
520
+ }
521
+ try {
522
+ _loggerProxy.default.info(`Pausing recording`, {
523
+ module: _constants.CC_FILE,
524
+ method: 'pauseRecording',
525
+ interactionId: this.data.interactionId
526
+ });
527
+ this.metricsManager.timeEvent([_constants2.METRIC_EVENT_NAMES.TASK_PAUSE_RECORDING_SUCCESS, _constants2.METRIC_EVENT_NAMES.TASK_PAUSE_RECORDING_FAILED]);
528
+ const result = await this.contact.pauseRecording({
529
+ interactionId: this.data.interactionId
530
+ });
531
+ this.metricsManager.trackEvent(_constants2.METRIC_EVENT_NAMES.TASK_PAUSE_RECORDING_SUCCESS, {
532
+ taskId: this.data.interactionId,
533
+ ..._MetricsManager.default.getCommonTrackingFieldForAQMResponse(result)
534
+ }, ['operational', 'behavioral', 'business']);
535
+ _loggerProxy.default.log(`Recording paused successfully`, {
536
+ module: _constants.CC_FILE,
537
+ method: 'pauseRecording',
538
+ trackingId: result.trackingId,
539
+ interactionId: this.data.interactionId
540
+ });
541
+ return result;
542
+ } catch (error) {
543
+ const {
544
+ error: detailedError
545
+ } = (0, _Utils.getErrorDetails)(error, 'pauseRecording', _constants.CC_FILE);
546
+ this.metricsManager.trackEvent(_constants2.METRIC_EVENT_NAMES.TASK_PAUSE_RECORDING_FAILED, {
547
+ taskId: this.data.interactionId,
548
+ error: error.toString(),
549
+ ..._MetricsManager.default.getCommonTrackingFieldForAQMResponseFailed(error.details || {})
550
+ }, ['operational', 'behavioral', 'business']);
551
+ throw detailedError;
552
+ }
553
+ }
554
+
555
+ /**
556
+ * This is used to pause the call recording
557
+ * @param resumeRecordingPayload
558
+ * @returns Promise<TaskResponse>
559
+ * @throws Error
560
+ * @example
561
+ * ```typescript
562
+ * task.resumeRecording(resumeRecordingPayload).then(()=>{}).catch(()=>{});
563
+ * ```
564
+ */
565
+ async resumeRecording(resumeRecordingPayload) {
566
+ // Validate recording is paused
567
+ const state = this.getStateMachineSnapshot();
568
+ if (state) {
569
+ const {
570
+ recordingControlsAvailable,
571
+ recordingInProgress
572
+ } = state.context;
573
+ const recordingPaused = Boolean(recordingControlsAvailable && !recordingInProgress);
574
+ if (!recordingPaused) {
575
+ const error = new Error('Recording is not paused');
576
+ _loggerProxy.default.error('Resume recording operation not allowed', {
577
+ module: _constants.CC_FILE,
578
+ method: 'resumeRecording',
579
+ interactionId: this.data.interactionId
580
+ });
581
+ throw error;
582
+ }
583
+ }
584
+ try {
585
+ _loggerProxy.default.info(`Resuming recording`, {
586
+ module: _constants.CC_FILE,
587
+ method: 'resumeRecording',
588
+ interactionId: this.data.interactionId
589
+ });
590
+ this.metricsManager.timeEvent([_constants2.METRIC_EVENT_NAMES.TASK_RESUME_RECORDING_SUCCESS, _constants2.METRIC_EVENT_NAMES.TASK_RESUME_RECORDING_FAILED]);
591
+ resumeRecordingPayload ??= {
592
+ autoResumed: false
593
+ };
594
+ const result = await this.contact.resumeRecording({
595
+ interactionId: this.data.interactionId,
596
+ data: resumeRecordingPayload
597
+ });
598
+ this.metricsManager.trackEvent(_constants2.METRIC_EVENT_NAMES.TASK_RESUME_RECORDING_SUCCESS, {
599
+ taskId: this.data.interactionId,
600
+ ..._MetricsManager.default.getCommonTrackingFieldForAQMResponse(result)
601
+ }, ['operational', 'behavioral', 'business']);
602
+ _loggerProxy.default.log(`Recording resumed successfully`, {
603
+ module: _constants.CC_FILE,
604
+ method: 'resumeRecording',
605
+ trackingId: result.trackingId,
606
+ interactionId: this.data.interactionId
607
+ });
608
+ return result;
609
+ } catch (error) {
610
+ const {
611
+ error: detailedError
612
+ } = (0, _Utils.getErrorDetails)(error, 'resumeRecording', _constants.CC_FILE);
613
+ this.metricsManager.trackEvent(_constants2.METRIC_EVENT_NAMES.TASK_RESUME_RECORDING_FAILED, {
614
+ taskId: this.data.interactionId,
615
+ error: error.toString(),
616
+ ..._MetricsManager.default.getCommonTrackingFieldForAQMResponseFailed(error.details || {})
617
+ }, ['operational', 'behavioral', 'business']);
618
+ throw detailedError;
619
+ }
620
+ }
621
+
622
+ /**
623
+ * This is used to consult the task
624
+ * @param consultPayload
625
+ * @returns Promise<TaskResponse>
626
+ * @throws Error
627
+ * @example
628
+ * ```typescript
629
+ * const consultPayload = {
630
+ * destination: 'myBuddyAgentId',
631
+ * destinationType: DESTINATION_TYPE.AGENT,
632
+ * }
633
+ * task.consult(consultPayload).then(()=>{}).catch(()=>{});
634
+ * ```
635
+ * */
636
+ async consult(consultPayload) {
637
+ // Validate consult is allowed
638
+ const state = this.getStateMachineSnapshot();
639
+ const canConsult = state && (state.matches(_stateMachine.TaskState.CONNECTED) || state.matches(_stateMachine.TaskState.HELD) || state.matches(_stateMachine.TaskState.CONFERENCING));
640
+ if (!canConsult) {
641
+ const currentState = state?.value;
642
+ const error = new Error(`Cannot initiate consult in ${currentState} state`);
643
+ _loggerProxy.default.error('Consult operation not allowed', {
644
+ module: _constants.CC_FILE,
645
+ method: 'consult',
646
+ interactionId: this.data.interactionId
647
+ });
648
+ throw error;
649
+ }
650
+
651
+ // Send initiating event to transition to CONSULT_INITIATING state
652
+ if (this.stateMachineService) {
653
+ this.stateMachineService.send({
654
+ type: _stateMachine.TaskEvent.CONSULT,
655
+ destination: consultPayload.to,
656
+ destinationType: consultPayload.destinationType
657
+ });
658
+ }
659
+ const requestInteractionId = this.data.interaction?.mainInteractionId || this.data.interactionId;
660
+ try {
661
+ _loggerProxy.default.info(`Starting consult`, {
662
+ module: _constants.CC_FILE,
663
+ method: 'consult',
664
+ interactionId: requestInteractionId
665
+ });
666
+ this.metricsManager.timeEvent([_constants2.METRIC_EVENT_NAMES.TASK_CONSULT_START_SUCCESS, _constants2.METRIC_EVENT_NAMES.TASK_CONSULT_START_FAILED]);
667
+ const result = await this.contact.consult({
668
+ interactionId: requestInteractionId,
669
+ data: consultPayload
670
+ });
671
+
672
+ // Send success event to transition to CONSULTING state
673
+ if (this.stateMachineService) {
674
+ this.stateMachineService.send({
675
+ type: _stateMachine.TaskEvent.CONSULT_SUCCESS,
676
+ taskData: result.data
677
+ });
678
+ }
679
+ this.metricsManager.trackEvent(_constants2.METRIC_EVENT_NAMES.TASK_CONSULT_START_SUCCESS, {
680
+ taskId: this.data.interactionId,
681
+ requestInteractionId,
682
+ destination: consultPayload.to,
683
+ destinationType: consultPayload.destinationType,
684
+ ..._MetricsManager.default.getCommonTrackingFieldForAQMResponse(result)
685
+ }, ['operational', 'behavioral', 'business']);
686
+ _loggerProxy.default.log(`Consult successfully initiated to ${consultPayload.to}`, {
687
+ module: _constants.CC_FILE,
688
+ method: 'consult',
689
+ trackingId: result.trackingId,
690
+ interactionId: requestInteractionId
691
+ });
692
+ return result;
693
+ } catch (error) {
694
+ this.stateMachineService.send({
695
+ type: _stateMachine.TaskEvent.CONSULT_FAILED,
696
+ reason: error.toString()
697
+ });
698
+ const {
699
+ error: detailedError
700
+ } = (0, _Utils.getErrorDetails)(error, 'consult', _constants.CC_FILE);
701
+ this.metricsManager.trackEvent(_constants2.METRIC_EVENT_NAMES.TASK_CONSULT_START_FAILED, {
702
+ taskId: this.data.interactionId,
703
+ requestInteractionId,
704
+ destination: consultPayload.to,
705
+ destinationType: consultPayload.destinationType,
706
+ error: error.toString(),
707
+ ..._MetricsManager.default.getCommonTrackingFieldForAQMResponseFailed(error.details || {})
708
+ }, ['operational', 'behavioral', 'business']);
709
+ throw detailedError;
710
+ }
711
+ }
712
+
713
+ /**
714
+ * This is used to end the consult session on the task.
715
+ * @param consultEndPayload - Payload indicating consult end flags and identifiers
716
+ * @returns Promise<TaskResponse>
717
+ * @throws Error
718
+ * @example
719
+ * ```typescript
720
+ * task.endConsult({
721
+ * isConsult: true,
722
+ * queueId: 'myQueueId',
723
+ * taskId: 'taskId',
724
+ * });
725
+ * ```
726
+ */
727
+ async endConsult(consultEndPayload) {
728
+ const requestInteractionId = this.data.interaction?.mainInteractionId || this.data.interactionId;
729
+ try {
730
+ _loggerProxy.default.info(`Ending consult`, {
731
+ module: _constants.CC_FILE,
732
+ method: 'endConsult',
733
+ interactionId: requestInteractionId
734
+ });
735
+ this.metricsManager.timeEvent([_constants2.METRIC_EVENT_NAMES.TASK_CONSULT_END_SUCCESS, _constants2.METRIC_EVENT_NAMES.TASK_CONSULT_END_FAILED]);
736
+ const result = await this.contact.consultEnd({
737
+ interactionId: requestInteractionId,
738
+ data: consultEndPayload
739
+ });
740
+ this.metricsManager.trackEvent(_constants2.METRIC_EVENT_NAMES.TASK_CONSULT_END_SUCCESS, {
741
+ taskId: this.data.interactionId,
742
+ requestInteractionId,
743
+ ..._MetricsManager.default.getCommonTrackingFieldForAQMResponse(result)
744
+ }, ['operational', 'behavioral', 'business']);
745
+ _loggerProxy.default.log(`Consult ended successfully`, {
746
+ module: _constants.CC_FILE,
747
+ method: 'endConsult',
748
+ trackingId: result.trackingId,
749
+ interactionId: this.data.interactionId
750
+ });
751
+ return result;
752
+ } catch (error) {
753
+ const {
754
+ error: detailedError
755
+ } = (0, _Utils.getErrorDetails)(error, 'endConsult', _constants.CC_FILE);
756
+ this.metricsManager.trackEvent(_constants2.METRIC_EVENT_NAMES.TASK_CONSULT_END_FAILED, {
757
+ taskId: this.data.interactionId,
758
+ requestInteractionId,
759
+ error: error.toString(),
760
+ ..._MetricsManager.default.getCommonTrackingFieldForAQMResponseFailed(error.details || {})
761
+ }, ['operational', 'behavioral', 'business']);
762
+ throw detailedError;
763
+ }
764
+ }
765
+
766
+ /**
767
+ * This is used to transfer the task.
768
+ * @param payload - Transfer payload
769
+ * @returns Promise<TaskResponse>
770
+ * @throws Error
771
+ * @example
772
+ * ```typescript
773
+ * task.transfer({
774
+ * to: 'destinationId',
775
+ * destinationType: DESTINATION_TYPE.AGENT,
776
+ * consult: true, // Optional, if true will perform a consult transfer else blind transfer
777
+ * });
778
+ * ```
779
+ */
780
+ async transfer(payload) {
781
+ try {
782
+ _loggerProxy.default.info(`Transferring task to ${payload.to}`, {
783
+ module: _constants.CC_FILE,
784
+ method: _constants.METHODS.TRANSFER_CALL,
785
+ interactionId: this.data.interactionId
786
+ });
787
+ this.metricsManager.timeEvent([_constants2.METRIC_EVENT_NAMES.TASK_TRANSFER_SUCCESS, _constants2.METRIC_EVENT_NAMES.TASK_TRANSFER_FAILED]);
788
+
789
+ // consult transfer path
790
+ if (this.data.interaction.state === 'consulting') {
791
+ const normalizedDestinationType = payload.destinationType === 'Agent' || payload.destinationType === 'Queue' ? payload.destinationType.toLowerCase() : payload.destinationType;
792
+ let consultPayload = {
793
+ to: payload.to,
794
+ destinationType: normalizedDestinationType
795
+ };
796
+ if (normalizedDestinationType === _types.CONSULT_TRANSFER_DESTINATION_TYPE.QUEUE) {
797
+ const consultContext = this.getStateMachineSnapshot()?.context;
798
+ const destAgent = consultContext?.consultDestinationAgentId || this.data.destAgentId;
799
+ if (!destAgent) {
800
+ throw new Error('No agent has accepted this queue consult yet');
801
+ }
802
+ consultPayload = {
803
+ to: destAgent,
804
+ destinationType: _types.CONSULT_TRANSFER_DESTINATION_TYPE.AGENT
805
+ };
806
+ }
807
+ const result = await this.contact.consultTransfer({
808
+ interactionId: this.data.interactionId,
809
+ data: consultPayload
810
+ });
811
+ this.metricsManager.trackEvent(_constants2.METRIC_EVENT_NAMES.TASK_TRANSFER_SUCCESS, {
812
+ taskId: this.data.interactionId,
813
+ destination: consultPayload.to,
814
+ destinationType: consultPayload.destinationType,
815
+ isConsultTransfer: true,
816
+ ..._MetricsManager.default.getCommonTrackingFieldForAQMResponse(result)
817
+ }, ['operational', 'behavioral', 'business']);
818
+ _loggerProxy.default.log(`Consult transfer completed successfully to ${consultPayload.to}`, {
819
+ module: _constants.CC_FILE,
820
+ method: _constants.METHODS.TRANSFER_CALL,
821
+ trackingId: result.trackingId,
822
+ interactionId: this.data.interactionId
823
+ });
824
+ return result;
825
+ }
826
+
827
+ // standard blind transfer
828
+ return await super.transfer({
829
+ to: payload.to,
830
+ destinationType: payload.destinationType
831
+ });
832
+ } catch (err) {
833
+ const {
834
+ error: detailedError
835
+ } = (0, _Utils.getErrorDetails)(err, _constants.METHODS.TRANSFER_CALL, _constants.CC_FILE);
836
+ this.metricsManager.trackEvent(_constants2.METRIC_EVENT_NAMES.TASK_TRANSFER_FAILED, {
837
+ taskId: this.data.interactionId,
838
+ destination: payload.to,
839
+ destinationType: payload.destinationType,
840
+ isConsultTransfer: this.data.interaction.state === 'consulting',
841
+ error: err.toString(),
842
+ ..._MetricsManager.default.getCommonTrackingFieldForAQMResponseFailed(err.details || {})
843
+ }, ['operational', 'behavioral', 'business']);
844
+ throw detailedError;
845
+ }
846
+ }
847
+
848
+ /**
849
+ * Start a consult conference, merging main and consult calls.
850
+ */
851
+ async consultConference() {
852
+ const derivedDestAgentId = this.data.interaction && this.data.agentId ? (0, _Utils.calculateDestAgentId)(this.data.interaction, this.data.agentId) : '';
853
+ const derivedDestType = this.data.interaction && this.data.agentId ? (0, _Utils.calculateDestType)(this.data.interaction, this.data.agentId) : '';
854
+
855
+ // derivedDestType is most reliable as it inspects live interaction participants
856
+ const resolvedDestinationType = derivedDestType || this.getStateMachineSnapshot()?.context?.consultDestinationType || this.data.destinationType || 'agent';
857
+ const consultationData = {
858
+ agentId: this.data.agentId,
859
+ destinationType: resolvedDestinationType,
860
+ // derivedDestAgentId is most reliable as it resolves epId for EP_DN
861
+ // and agent ID for regular agents from live interaction data
862
+ destAgentId: derivedDestAgentId || this.getStateMachineSnapshot()?.context?.consultDestinationAgentId || this.data.destAgentId
863
+ };
864
+
865
+ // Send state machine event to transition to CONF_INITIATING
866
+ if (this.stateMachineService) {
867
+ this.stateMachineService.send({
868
+ type: _stateMachine.TaskEvent.MERGE_TO_CONFERENCE
869
+ });
870
+ }
871
+ try {
872
+ if (!consultationData.destAgentId) {
873
+ throw new Error('Unable to determine consult destination for conference');
874
+ }
875
+ _loggerProxy.default.info(`Initiating consult conference to ${consultationData.destAgentId}`, {
876
+ module: _constants.CC_FILE,
877
+ method: _constants.METHODS.CONSULT_CONFERENCE,
878
+ interactionId: this.data.interactionId
879
+ });
880
+ const paramsDataForConferenceV2 = (0, _Utils.buildConsultConferenceParamData)(consultationData, this.data.interactionId);
881
+ const response = await this.contact.consultConference({
882
+ interactionId: paramsDataForConferenceV2.interactionId,
883
+ data: paramsDataForConferenceV2.data
884
+ });
885
+
886
+ // Send success event to transition to CONFERENCING
887
+ if (this.stateMachineService) {
888
+ this.stateMachineService.send({
889
+ type: _stateMachine.TaskEvent.CONFERENCE_START
890
+ });
891
+ }
892
+ this.metricsManager.trackEvent(_constants2.METRIC_EVENT_NAMES.TASK_CONFERENCE_START_SUCCESS, {
893
+ taskId: this.data.interactionId,
894
+ destination: paramsDataForConferenceV2.data.to,
895
+ destinationType: paramsDataForConferenceV2.data.destinationType,
896
+ agentId: paramsDataForConferenceV2.data.agentId,
897
+ ..._MetricsManager.default.getCommonTrackingFieldForAQMResponse(response)
898
+ }, ['operational', 'behavioral', 'business']);
899
+ _loggerProxy.default.log(`Consult conference started successfully`, {
900
+ module: _constants.CC_FILE,
901
+ method: _constants.METHODS.CONSULT_CONFERENCE,
902
+ interactionId: this.data.interactionId
903
+ });
904
+ return response;
905
+ } catch (error) {
906
+ // Send failure event to revert state
907
+ if (this.stateMachineService) {
908
+ this.stateMachineService.send({
909
+ type: _stateMachine.TaskEvent.CONFERENCE_FAILED,
910
+ reason: error.toString()
911
+ });
912
+ }
913
+ const {
914
+ error: detailedError
915
+ } = (0, _Utils.getErrorDetails)(error, _constants.METHODS.CONSULT_CONFERENCE, _constants.CC_FILE);
916
+ const failedParamsData = (0, _Utils.buildConsultConferenceParamData)(consultationData, this.data.interactionId);
917
+ this.metricsManager.trackEvent(_constants2.METRIC_EVENT_NAMES.TASK_CONFERENCE_START_FAILED, {
918
+ taskId: this.data.interactionId,
919
+ destination: failedParamsData.data.to,
920
+ destinationType: failedParamsData.data.destinationType,
921
+ agentId: failedParamsData.data.agentId,
922
+ error: error.toString(),
923
+ ..._MetricsManager.default.getCommonTrackingFieldForAQMResponseFailed(error.details || {})
924
+ }, ['operational', 'behavioral', 'business']);
925
+ _loggerProxy.default.error(`Failed to start consult conference`, {
926
+ module: _constants.CC_FILE,
927
+ method: _constants.METHODS.CONSULT_CONFERENCE,
928
+ interactionId: this.data.interactionId
929
+ });
930
+ throw detailedError;
931
+ }
932
+ }
933
+
934
+ /**
935
+ * Removes another participant from an active conference.
936
+ * Completion is correlated with ParticipantLeftConference by the AQM request layer.
937
+ * @param payload - Participant identifier to remove
938
+ * @returns Promise<TaskResponse>
939
+ */
940
+ async dropConferenceParticipant(payload) {
941
+ // The TypeScript contract requires payload, but the published SDK is also callable from
942
+ // untyped JavaScript. Keep an explicit runtime boundary check before direct property access.
943
+ if (!payload) {
944
+ throw new Error('participantId must be a non-empty string');
945
+ }
946
+ const {
947
+ participantId
948
+ } = payload;
949
+ if (typeof participantId !== 'string' || participantId.trim().length === 0) {
950
+ throw new Error('participantId must be a non-empty string');
951
+ }
952
+ const requestInteractionId = this.data.interaction?.mainInteractionId || this.data.interactionId;
953
+ // taskId identifies the SDK task instance, which can remain child-interaction keyed after
954
+ // consult/EP-DN flows. requestInteractionId identifies the main interaction sent to AQM.
955
+
956
+ _loggerProxy.default.info('Dropping conference participant', {
957
+ module: _constants.CC_FILE,
958
+ method: _constants.METHODS.DROP_CONFERENCE_PARTICIPANT,
959
+ interactionId: requestInteractionId
960
+ });
961
+ try {
962
+ this.metricsManager.timeEvent([_constants2.METRIC_EVENT_NAMES.TASK_CONFERENCE_PARTICIPANT_DROP_SUCCESS, _constants2.METRIC_EVENT_NAMES.TASK_CONFERENCE_PARTICIPANT_DROP_FAILED]);
963
+ const response = await this.contact.dropConferenceParticipant({
964
+ interactionId: requestInteractionId,
965
+ participantId
966
+ });
967
+ this.metricsManager.trackEvent(_constants2.METRIC_EVENT_NAMES.TASK_CONFERENCE_PARTICIPANT_DROP_SUCCESS, {
968
+ taskId: this.data.interactionId,
969
+ requestInteractionId,
970
+ ..._MetricsManager.default.getCommonTrackingFieldForAQMResponse(response),
971
+ agentId: this.agentId
972
+ }, ['operational', 'behavioral', 'business']);
973
+ _loggerProxy.default.log('Successfully dropped conference participant', {
974
+ module: _constants.CC_FILE,
975
+ method: _constants.METHODS.DROP_CONFERENCE_PARTICIPANT,
976
+ trackingId: response?.trackingId,
977
+ interactionId: requestInteractionId
978
+ });
979
+ return response;
980
+ } catch (error) {
981
+ const failureTrackingFields = _MetricsManager.default.getCommonTrackingFieldForAQMResponseFailed(error?.details || {});
982
+ this.metricsManager.trackEvent(_constants2.METRIC_EVENT_NAMES.TASK_CONFERENCE_PARTICIPANT_DROP_FAILED, {
983
+ taskId: this.data.interactionId,
984
+ requestInteractionId,
985
+ agentId: this.agentId,
986
+ trackingId: failureTrackingFields.trackingId,
987
+ notifTrackingId: failureTrackingFields.notifTrackingId,
988
+ orgId: failureTrackingFields.orgId,
989
+ failureType: failureTrackingFields.failureType,
990
+ reasonCode: failureTrackingFields.reasonCode
991
+ }, ['operational', 'behavioral', 'business']);
992
+ _loggerProxy.default.error('Failed to drop conference participant', {
993
+ module: _constants.CC_FILE,
994
+ method: _constants.METHODS.DROP_CONFERENCE_PARTICIPANT,
995
+ trackingId: failureTrackingFields.trackingId,
996
+ interactionId: requestInteractionId
997
+ });
998
+ throw error;
999
+ }
1000
+ }
1001
+
1002
+ /**
1003
+ * Exit from a conference call.
1004
+ * Per conference-spec.md:
1005
+ * - Primary agent exits to wrapup
1006
+ * - Non-primary agent exits to available/connected
1007
+ * - Other participants continue the call
1008
+ *
1009
+ * @returns Promise<TaskResponse>
1010
+ * @throws Error if not in conference or exit fails
1011
+ * @example
1012
+ * ```typescript
1013
+ * task.exitConference().then(() => {}).catch(() => {});
1014
+ * ```
1015
+ */
1016
+ async exitConference() {
1017
+ // Validate we're in conference state OR conference is in progress per task data
1018
+ // This handles cases where:
1019
+ // 1. State machine is in CONFERENCING state
1020
+ // 2. State machine is in CONNECTED but conference is active (e.g., ownership transferred)
1021
+ const state = this.getStateMachineSnapshot();
1022
+ const isConferencingState = state?.matches(_stateMachine.TaskState.CONFERENCING);
1023
+ const isConferenceInProgressFromData = this.data ? (0, _TaskUtils.getIsConferenceInProgress)(this.data) : false;
1024
+ if (!state || !isConferencingState && !isConferenceInProgressFromData) {
1025
+ const currentState = state?.value;
1026
+ const error = new Error(`Cannot exit conference in ${currentState} state`);
1027
+ _loggerProxy.default.error('Exit conference operation not allowed', {
1028
+ module: _constants.CC_FILE,
1029
+ method: 'exitConference',
1030
+ interactionId: this.data.interactionId
1031
+ });
1032
+ throw error;
1033
+ }
1034
+
1035
+ // Send state machine event
1036
+ if (this.stateMachineService) {
1037
+ this.stateMachineService.send({
1038
+ type: _stateMachine.TaskEvent.EXIT_CONFERENCE,
1039
+ agentId: this.data.agentId
1040
+ });
1041
+ }
1042
+ const requestInteractionId = this.data.interaction?.mainInteractionId || this.data.interactionId;
1043
+ try {
1044
+ _loggerProxy.default.info(`Exiting conference`, {
1045
+ module: _constants.CC_FILE,
1046
+ method: 'exitConference',
1047
+ interactionId: requestInteractionId
1048
+ });
1049
+ this.metricsManager.timeEvent([_constants2.METRIC_EVENT_NAMES.TASK_CONFERENCE_EXIT_SUCCESS, _constants2.METRIC_EVENT_NAMES.TASK_CONFERENCE_EXIT_FAILED]);
1050
+ const response = await this.contact.exitConference({
1051
+ interactionId: requestInteractionId
1052
+ });
1053
+
1054
+ // Send success event to transition state
1055
+ if (this.stateMachineService) {
1056
+ this.stateMachineService.send({
1057
+ type: _stateMachine.TaskEvent.EXIT_CONFERENCE_SUCCESS,
1058
+ taskData: response.data
1059
+ });
1060
+ }
1061
+ this.metricsManager.trackEvent(_constants2.METRIC_EVENT_NAMES.TASK_CONFERENCE_EXIT_SUCCESS, {
1062
+ taskId: this.data.interactionId,
1063
+ requestInteractionId,
1064
+ agentId: this.data.agentId,
1065
+ ..._MetricsManager.default.getCommonTrackingFieldForAQMResponse(response)
1066
+ }, ['operational', 'behavioral', 'business']);
1067
+ _loggerProxy.default.log(`Successfully exited conference`, {
1068
+ module: _constants.CC_FILE,
1069
+ method: 'exitConference',
1070
+ trackingId: response.trackingId,
1071
+ interactionId: requestInteractionId
1072
+ });
1073
+ return response;
1074
+ } catch (error) {
1075
+ // Send failure event
1076
+ if (this.stateMachineService) {
1077
+ this.stateMachineService.send({
1078
+ type: _stateMachine.TaskEvent.EXIT_CONFERENCE_FAILED,
1079
+ reason: error.toString()
1080
+ });
1081
+ }
1082
+ const {
1083
+ error: detailedError
1084
+ } = (0, _Utils.getErrorDetails)(error, 'exitConference', _constants.CC_FILE);
1085
+ this.metricsManager.trackEvent(_constants2.METRIC_EVENT_NAMES.TASK_CONFERENCE_EXIT_FAILED, {
1086
+ taskId: this.data.interactionId,
1087
+ requestInteractionId,
1088
+ agentId: this.data.agentId,
1089
+ error: error.toString(),
1090
+ ..._MetricsManager.default.getCommonTrackingFieldForAQMResponseFailed(error.details || {})
1091
+ }, ['operational', 'behavioral', 'business']);
1092
+ _loggerProxy.default.error(`Failed to exit conference`, {
1093
+ module: _constants.CC_FILE,
1094
+ method: 'exitConference',
1095
+ interactionId: requestInteractionId
1096
+ });
1097
+ throw detailedError;
1098
+ }
1099
+ }
1100
+
1101
+ /**
1102
+ * Transfer the conference to another participant.
1103
+ * Per conference-spec.md: Only primary agent can transfer conference.
1104
+ * After transfer, the transferring agent exits to wrapup.
1105
+ *
1106
+ * @returns Promise<TaskResponse>
1107
+ * @throws Error if not in conference or transfer fails
1108
+ * @example
1109
+ * ```typescript
1110
+ * task.transferConference().then(() => {}).catch(() => {});
1111
+ * ```
1112
+ */
1113
+ async transferConference() {
1114
+ // Validate we're in conference or consulting state
1115
+ // CONSULTING is allowed because agent can transfer conference while consulting
1116
+ // (transfers ownership to the consulted agent)
1117
+ const state = this.getStateMachineSnapshot();
1118
+ const isValidState = state && (state.matches(_stateMachine.TaskState.CONFERENCING) || state.matches(_stateMachine.TaskState.CONSULTING));
1119
+ if (!isValidState) {
1120
+ const currentState = state?.value;
1121
+ const error = new Error(`Cannot transfer conference in ${currentState} state`);
1122
+ _loggerProxy.default.error('Transfer conference operation not allowed', {
1123
+ module: _constants.CC_FILE,
1124
+ method: 'transferConference',
1125
+ interactionId: this.data.interactionId
1126
+ });
1127
+ throw error;
1128
+ }
1129
+
1130
+ // Send state machine event
1131
+ if (this.stateMachineService) {
1132
+ this.stateMachineService.send({
1133
+ type: _stateMachine.TaskEvent.TRANSFER_CONFERENCE,
1134
+ agentId: this.data.agentId
1135
+ });
1136
+ }
1137
+ const requestInteractionId = this.data.interaction?.mainInteractionId || this.data.interactionId;
1138
+ try {
1139
+ _loggerProxy.default.info(`Transferring conference`, {
1140
+ module: _constants.CC_FILE,
1141
+ method: 'transferConference',
1142
+ interactionId: requestInteractionId
1143
+ });
1144
+ this.metricsManager.timeEvent([_constants2.METRIC_EVENT_NAMES.TASK_CONFERENCE_TRANSFER_SUCCESS, _constants2.METRIC_EVENT_NAMES.TASK_CONFERENCE_TRANSFER_FAILED]);
1145
+ const response = await this.contact.conferenceTransfer({
1146
+ interactionId: requestInteractionId
1147
+ });
1148
+
1149
+ // Send success event to transition state
1150
+ if (this.stateMachineService) {
1151
+ this.stateMachineService.send({
1152
+ type: _stateMachine.TaskEvent.TRANSFER_CONFERENCE_SUCCESS,
1153
+ taskData: response.data
1154
+ });
1155
+ }
1156
+ this.metricsManager.trackEvent(_constants2.METRIC_EVENT_NAMES.TASK_CONFERENCE_TRANSFER_SUCCESS, {
1157
+ taskId: this.data.interactionId,
1158
+ requestInteractionId,
1159
+ agentId: this.data.agentId,
1160
+ ..._MetricsManager.default.getCommonTrackingFieldForAQMResponse(response)
1161
+ }, ['operational', 'behavioral', 'business']);
1162
+ _loggerProxy.default.log(`Successfully transferred conference`, {
1163
+ module: _constants.CC_FILE,
1164
+ method: 'transferConference',
1165
+ trackingId: response.trackingId,
1166
+ interactionId: requestInteractionId
1167
+ });
1168
+ return response;
1169
+ } catch (error) {
1170
+ // Send failure event
1171
+ if (this.stateMachineService) {
1172
+ this.stateMachineService.send({
1173
+ type: _stateMachine.TaskEvent.TRANSFER_CONFERENCE_FAILED,
1174
+ reason: error.toString()
1175
+ });
1176
+ }
1177
+ const {
1178
+ error: detailedError
1179
+ } = (0, _Utils.getErrorDetails)(error, 'transferConference', _constants.CC_FILE);
1180
+ this.metricsManager.trackEvent(_constants2.METRIC_EVENT_NAMES.TASK_CONFERENCE_TRANSFER_FAILED, {
1181
+ taskId: this.data.interactionId,
1182
+ requestInteractionId,
1183
+ agentId: this.data.agentId,
1184
+ error: error.toString(),
1185
+ ..._MetricsManager.default.getCommonTrackingFieldForAQMResponseFailed(error.details || {})
1186
+ }, ['operational', 'behavioral', 'business']);
1187
+ _loggerProxy.default.error(`Failed to transfer conference`, {
1188
+ module: _constants.CC_FILE,
1189
+ method: 'transferConference',
1190
+ interactionId: requestInteractionId
1191
+ });
1192
+ throw detailedError;
1193
+ }
1194
+ }
1195
+
1196
+ /**
1197
+ * Toggle between consult call and main call during consulting.
1198
+ * If on consult leg (consultCallHeld = false), switches to main call by holding consult.
1199
+ * If on main call (consultCallHeld = true), switches to consult by resuming consult.
1200
+ *
1201
+ * @returns Promise<TaskResponse>
1202
+ * @throws Error if not in CONSULTING state or no consult media resource
1203
+ * @example
1204
+ * ```typescript
1205
+ * await task.switchCall();
1206
+ * ```
1207
+ */
1208
+ async switchCall() {
1209
+ // Validate we're in CONSULTING state
1210
+ const state = this.getStateMachineSnapshot();
1211
+ if (!state?.matches(_stateMachine.TaskState.CONSULTING)) {
1212
+ const currentState = state?.value;
1213
+ const error = new Error(`Cannot switch call in ${currentState} state`);
1214
+ _loggerProxy.default.error('Switch call operation not allowed', {
1215
+ module: _constants.CC_FILE,
1216
+ method: 'switchCall',
1217
+ interactionId: this.data.interactionId
1218
+ });
1219
+ throw error;
1220
+ }
1221
+
1222
+ // Validate we have a consult media resource
1223
+ const consultMediaResourceId = (0, _TaskUtils.getConsultMediaResourceId)(this.data.interaction, this.data.consultMediaResourceId, this.data.agentId);
1224
+ if (!consultMediaResourceId) {
1225
+ const error = new Error('No consult media resource available');
1226
+ _loggerProxy.default.error('Switch call failed - no consult media resource', {
1227
+ module: _constants.CC_FILE,
1228
+ method: 'switchCall',
1229
+ interactionId: this.data.interactionId
1230
+ });
1231
+ throw error;
1232
+ }
1233
+ const context = state.context;
1234
+ const isOnConsultLeg = !context.consultCallHeld;
1235
+
1236
+ // Determine direction and send appropriate state machine event
1237
+ const targetEvent = isOnConsultLeg ? _stateMachine.TaskEvent.SWITCH_TO_MAIN_CALL : _stateMachine.TaskEvent.SWITCH_TO_CONSULT;
1238
+ const revertEvent = isOnConsultLeg ? _stateMachine.TaskEvent.SWITCH_TO_CONSULT : _stateMachine.TaskEvent.SWITCH_TO_MAIN_CALL;
1239
+ if (this.stateMachineService) {
1240
+ this.stateMachineService.send({
1241
+ type: targetEvent
1242
+ });
1243
+ }
1244
+ this.metricsManager.timeEvent([_constants2.METRIC_EVENT_NAMES.TASK_SWITCH_CALL_SUCCESS, _constants2.METRIC_EVENT_NAMES.TASK_SWITCH_CALL_FAILED]);
1245
+ try {
1246
+ if (isOnConsultLeg) {
1247
+ const response = await this.contact.unHold({
1248
+ interactionId: this.data.interactionId,
1249
+ data: {
1250
+ mediaResourceId: this.data.mediaResourceId
1251
+ }
1252
+ });
1253
+ this.metricsManager.trackEvent(_constants2.METRIC_EVENT_NAMES.TASK_SWITCH_CALL_SUCCESS, {
1254
+ taskId: this.data.interactionId,
1255
+ direction: 'toMainCall',
1256
+ mediaResourceId: consultMediaResourceId,
1257
+ ..._MetricsManager.default.getCommonTrackingFieldForAQMResponse(response)
1258
+ }, ['operational', 'behavioral']);
1259
+ _loggerProxy.default.log(`Switched to main call successfully`, {
1260
+ module: _constants.CC_FILE,
1261
+ method: 'switchCall',
1262
+ trackingId: response.trackingId,
1263
+ interactionId: this.data.interactionId
1264
+ });
1265
+ return response;
1266
+ }
1267
+ const response = await this.contact.hold({
1268
+ interactionId: this.data.interactionId,
1269
+ data: {
1270
+ mediaResourceId: this.data.mediaResourceId
1271
+ }
1272
+ });
1273
+ this.metricsManager.trackEvent(_constants2.METRIC_EVENT_NAMES.TASK_SWITCH_CALL_SUCCESS, {
1274
+ taskId: this.data.interactionId,
1275
+ direction: 'toConsultCall',
1276
+ mediaResourceId: consultMediaResourceId,
1277
+ ..._MetricsManager.default.getCommonTrackingFieldForAQMResponse(response)
1278
+ }, ['operational', 'behavioral']);
1279
+ _loggerProxy.default.log(`Switched to consult call successfully`, {
1280
+ module: _constants.CC_FILE,
1281
+ method: 'switchCall',
1282
+ trackingId: response.trackingId,
1283
+ interactionId: this.data.interactionId
1284
+ });
1285
+ return response;
1286
+ } catch (error) {
1287
+ if (this.stateMachineService) {
1288
+ this.stateMachineService.send({
1289
+ type: revertEvent
1290
+ });
1291
+ }
1292
+ this.metricsManager.trackEvent(_constants2.METRIC_EVENT_NAMES.TASK_SWITCH_CALL_FAILED, {
1293
+ taskId: this.data.interactionId,
1294
+ direction: isOnConsultLeg ? 'toMainCall' : 'toConsultCall',
1295
+ mediaResourceId: consultMediaResourceId,
1296
+ error: error.toString(),
1297
+ ..._MetricsManager.default.getCommonTrackingFieldForAQMResponseFailed(error.details || {})
1298
+ }, ['operational', 'behavioral']);
1299
+ const {
1300
+ error: detailedError
1301
+ } = (0, _Utils.getErrorDetails)(error, 'switchCall', _constants.CC_FILE);
1302
+ _loggerProxy.default.error(`Failed to switch call`, {
1303
+ module: _constants.CC_FILE,
1304
+ method: 'switchCall',
1305
+ interactionId: this.data.interactionId
1306
+ });
1307
+ throw detailedError;
1308
+ }
1309
+ }
1310
+ getChannelSpecificActionOverrides() {
1311
+ const baseOverrides = super.getChannelSpecificActionOverrides();
1312
+ return {
1313
+ ...baseOverrides,
1314
+ emitTaskHold: this.createEmitSelfAction(_types.TASK_EVENTS.TASK_HOLD, {
1315
+ updateTaskData: true
1316
+ }),
1317
+ emitTaskResume: this.createEmitSelfAction(_types.TASK_EVENTS.TASK_RESUME, {
1318
+ updateTaskData: true
1319
+ }),
1320
+ emitTaskRecordingStarted: this.createEmitSelfAction(_types.TASK_EVENTS.TASK_RECORDING_STARTED, {
1321
+ updateTaskData: true
1322
+ }),
1323
+ emitTaskRecordingPaused: this.createEmitSelfAction(_types.TASK_EVENTS.TASK_RECORDING_PAUSED, {
1324
+ updateTaskData: true
1325
+ }),
1326
+ emitTaskRecordingPauseFailed: this.createEmitSelfAction(_types.TASK_EVENTS.TASK_RECORDING_PAUSE_FAILED, {
1327
+ updateTaskData: true
1328
+ }),
1329
+ emitTaskRecordingResumed: this.createEmitSelfAction(_types.TASK_EVENTS.TASK_RECORDING_RESUMED, {
1330
+ updateTaskData: true
1331
+ }),
1332
+ emitTaskRecordingResumeFailed: this.createEmitSelfAction(_types.TASK_EVENTS.TASK_RECORDING_RESUME_FAILED, {
1333
+ updateTaskData: true
1334
+ }),
1335
+ // Conference event emitters
1336
+ emitTaskParticipantJoined: this.createEmitSelfAction(_types.TASK_EVENTS.TASK_PARTICIPANT_JOINED, {
1337
+ updateTaskData: true
1338
+ }),
1339
+ emitTaskParticipantLeft: this.createEmitSelfAction(_types.TASK_EVENTS.TASK_PARTICIPANT_LEFT, {
1340
+ updateTaskData: true
1341
+ }),
1342
+ emitTaskConferenceStarted: this.createEmitSelfAction(_types.TASK_EVENTS.TASK_CONFERENCE_STARTED, {
1343
+ updateTaskData: true
1344
+ }),
1345
+ emitTaskConferenceEnded: this.createEmitSelfAction(_types.TASK_EVENTS.TASK_CONFERENCE_ENDED, {
1346
+ updateTaskData: true
1347
+ }),
1348
+ emitTaskConferenceFailed: this.createEmitSelfAction(_types.TASK_EVENTS.TASK_CONFERENCE_FAILED, {
1349
+ updateTaskData: true
1350
+ }),
1351
+ emitTaskExitConference: this.createEmitSelfAction(_types.TASK_EVENTS.TASK_EXIT_CONFERENCE, {
1352
+ updateTaskData: false
1353
+ }),
1354
+ emitTaskTransferConference: this.createEmitSelfAction(_types.TASK_EVENTS.TASK_TRANSFER_CONFERENCE, {
1355
+ updateTaskData: false
1356
+ }),
1357
+ emitTaskSwitchCall: this.createEmitSelfAction(_types.TASK_EVENTS.TASK_SWITCH_CALL, {
1358
+ updateTaskData: false
1359
+ }),
1360
+ emitTaskTransferConferenceFailed: this.createEmitSelfAction(_types.TASK_EVENTS.TASK_CONFERENCE_TRANSFER_FAILED, {
1361
+ updateTaskData: true
1362
+ }),
1363
+ emitTaskOutdialFailed: ({
1364
+ event
1365
+ }) => {
1366
+ const taskData = event?.taskData;
1367
+ if (taskData) {
1368
+ this.updateTaskData(taskData);
1369
+ }
1370
+ if (taskData?.suppressOutdialFailedPopup) {
1371
+ return;
1372
+ }
1373
+ const reason = event?.reason || 'Outdial failed';
1374
+ this.emit(_types.TASK_EVENTS.TASK_OUTDIAL_FAILED, reason);
1375
+ }
1376
+ };
1377
+ }
1378
+ }
1379
+ exports.default = Voice;
1380
+ //# sourceMappingURL=Voice.js.map