@webex/contact-center 3.12.0-next.13 → 3.12.0-next.130

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 (312) hide show
  1. package/.sdd/manifest.json +884 -0
  2. package/AGENTS.md +94 -0
  3. package/ai-docs/ARCHITECTURE.md +168 -0
  4. package/ai-docs/CONTRACTS.md +53 -0
  5. package/ai-docs/GETTING_STARTED.md +168 -0
  6. package/ai-docs/GLOSSARY.md +43 -0
  7. package/ai-docs/README.md +138 -0
  8. package/ai-docs/REVIEW_CHECKLIST.md +41 -0
  9. package/ai-docs/RULES.md +444 -0
  10. package/ai-docs/SECURITY.md +52 -0
  11. package/ai-docs/SERVICE_STATE.md +52 -0
  12. package/ai-docs/SPEC_INDEX.md +65 -0
  13. package/ai-docs/adr/0001-spec-source-policy.md +55 -0
  14. package/ai-docs/adr/README.md +8 -0
  15. package/ai-docs/adr/_adr-template.md +31 -0
  16. package/ai-docs/contact-center-spec.md +382 -0
  17. package/ai-docs/features/consult-transfer-list-policy/spec/feature-spec.md +362 -0
  18. package/ai-docs/features/contact-owner-change-refactor.md +78 -0
  19. package/ai-docs/features/generated-spec-conformance-fidelity-remediation/spec/feature-spec.md +117 -0
  20. package/ai-docs/features/residual-warning-coverage-completion/spec/feature-spec.md +203 -0
  21. package/ai-docs/features/validator-code-fidelity-drift-fix/spec/feature-spec.md +315 -0
  22. package/ai-docs/patterns/event-driven-patterns.md +485 -0
  23. package/ai-docs/patterns/testing-patterns.md +480 -0
  24. package/ai-docs/patterns/typescript-patterns.md +365 -0
  25. package/ai-docs/templates/README.md +102 -0
  26. package/ai-docs/templates/documentation/create-agents-md.md +240 -0
  27. package/ai-docs/templates/documentation/create-architecture-md.md +295 -0
  28. package/ai-docs/templates/existing-service/bug-fix.md +254 -0
  29. package/ai-docs/templates/existing-service/feature-enhancement.md +450 -0
  30. package/ai-docs/templates/new-method/00-master.md +80 -0
  31. package/ai-docs/templates/new-method/01-requirements.md +232 -0
  32. package/ai-docs/templates/new-method/02-implementation.md +295 -0
  33. package/ai-docs/templates/new-method/03-tests.md +201 -0
  34. package/ai-docs/templates/new-method/04-validation.md +141 -0
  35. package/ai-docs/templates/new-service/00-master.md +109 -0
  36. package/ai-docs/templates/new-service/01-pre-questions.md +159 -0
  37. package/ai-docs/templates/new-service/02-code-generation.md +346 -0
  38. package/ai-docs/templates/new-service/03-integration.md +178 -0
  39. package/ai-docs/templates/new-service/04-test-generation.md +205 -0
  40. package/ai-docs/templates/new-service/05-validation.md +145 -0
  41. package/dist/cc.js +971 -42
  42. package/dist/cc.js.map +1 -1
  43. package/dist/config.js +13 -0
  44. package/dist/config.js.map +1 -1
  45. package/dist/constants.js +31 -3
  46. package/dist/constants.js.map +1 -1
  47. package/dist/index.js +45 -15
  48. package/dist/index.js.map +1 -1
  49. package/dist/metrics/MetricsManager.js +16 -0
  50. package/dist/metrics/MetricsManager.js.map +1 -1
  51. package/dist/metrics/behavioral-events.js +205 -0
  52. package/dist/metrics/behavioral-events.js.map +1 -1
  53. package/dist/metrics/constants.js +48 -4
  54. package/dist/metrics/constants.js.map +1 -1
  55. package/dist/services/AddressBook.js +18 -15
  56. package/dist/services/AddressBook.js.map +1 -1
  57. package/dist/services/AnswerCallOnWebexService.js +202 -0
  58. package/dist/services/AnswerCallOnWebexService.js.map +1 -0
  59. package/dist/services/ApiAiAssistant.js +269 -9
  60. package/dist/services/ApiAiAssistant.js.map +1 -1
  61. package/dist/services/EntryPoint.js +46 -68
  62. package/dist/services/EntryPoint.js.map +1 -1
  63. package/dist/services/Queue.js +27 -22
  64. package/dist/services/Queue.js.map +1 -1
  65. package/dist/services/UserPreference.js +427 -0
  66. package/dist/services/UserPreference.js.map +1 -0
  67. package/dist/services/WebexCrossClientService.js +222 -0
  68. package/dist/services/WebexCrossClientService.js.map +1 -0
  69. package/dist/services/WxAppTelephonyMercurySync.js +108 -0
  70. package/dist/services/WxAppTelephonyMercurySync.js.map +1 -0
  71. package/dist/services/config/Util.js +11 -4
  72. package/dist/services/config/Util.js.map +1 -1
  73. package/dist/services/config/constants.js +41 -7
  74. package/dist/services/config/constants.js.map +1 -1
  75. package/dist/services/config/index.js +51 -0
  76. package/dist/services/config/index.js.map +1 -1
  77. package/dist/services/config/types.js +57 -12
  78. package/dist/services/config/types.js.map +1 -1
  79. package/dist/services/core/Err.js.map +1 -1
  80. package/dist/services/core/Utils.js +111 -32
  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 +28 -14
  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 +2 -1
  88. package/dist/services/core/websocket/WebSocketManager.js.map +1 -1
  89. package/dist/services/core/websocket/types.js.map +1 -1
  90. package/dist/services/index.js +1 -1
  91. package/dist/services/index.js.map +1 -1
  92. package/dist/services/task/Task.js +754 -0
  93. package/dist/services/task/Task.js.map +1 -0
  94. package/dist/services/task/TaskFactory.js +49 -0
  95. package/dist/services/task/TaskFactory.js.map +1 -0
  96. package/dist/services/task/TaskManager.js +1172 -521
  97. package/dist/services/task/TaskManager.js.map +1 -1
  98. package/dist/services/task/TaskUtils.js +211 -27
  99. package/dist/services/task/TaskUtils.js.map +1 -1
  100. package/dist/services/task/WebexCallingUtils.js +70 -0
  101. package/dist/services/task/WebexCallingUtils.js.map +1 -0
  102. package/dist/services/task/constants.js +12 -2
  103. package/dist/services/task/constants.js.map +1 -1
  104. package/dist/services/task/contact.js +29 -0
  105. package/dist/services/task/contact.js.map +1 -1
  106. package/dist/services/task/dialer.js +78 -0
  107. package/dist/services/task/dialer.js.map +1 -1
  108. package/dist/services/task/digital/Digital.js +78 -0
  109. package/dist/services/task/digital/Digital.js.map +1 -0
  110. package/dist/services/task/state-machine/TaskStateMachine.js +982 -0
  111. package/dist/services/task/state-machine/TaskStateMachine.js.map +1 -0
  112. package/dist/services/task/state-machine/actions.js +572 -0
  113. package/dist/services/task/state-machine/actions.js.map +1 -0
  114. package/dist/services/task/state-machine/constants.js +161 -0
  115. package/dist/services/task/state-machine/constants.js.map +1 -0
  116. package/dist/services/task/state-machine/guards.js +379 -0
  117. package/dist/services/task/state-machine/guards.js.map +1 -0
  118. package/dist/services/task/state-machine/index.js +53 -0
  119. package/dist/services/task/state-machine/index.js.map +1 -0
  120. package/dist/services/task/state-machine/types.js +54 -0
  121. package/dist/services/task/state-machine/types.js.map +1 -0
  122. package/dist/services/task/state-machine/uiControlsComputer.js +703 -0
  123. package/dist/services/task/state-machine/uiControlsComputer.js.map +1 -0
  124. package/dist/services/task/taskDataNormalizer.js +99 -0
  125. package/dist/services/task/taskDataNormalizer.js.map +1 -0
  126. package/dist/services/task/types.js +228 -5
  127. package/dist/services/task/types.js.map +1 -1
  128. package/dist/services/task/voice/Voice.js +1485 -0
  129. package/dist/services/task/voice/Voice.js.map +1 -0
  130. package/dist/services/task/voice/WebRTC.js +152 -0
  131. package/dist/services/task/voice/WebRTC.js.map +1 -0
  132. package/dist/services/task/voice/wxAppVoiceMethods.js +354 -0
  133. package/dist/services/task/voice/wxAppVoiceMethods.js.map +1 -0
  134. package/dist/services/wxAppDiagnosticLogging.js +122 -0
  135. package/dist/services/wxAppDiagnosticLogging.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 +193 -6
  139. package/dist/types/config.d.ts +13 -0
  140. package/dist/types/constants.d.ts +29 -1
  141. package/dist/types/index.d.ts +35 -8
  142. package/dist/types/metrics/MetricsManager.d.ts +6 -0
  143. package/dist/types/metrics/constants.d.ts +43 -1
  144. package/dist/types/services/AddressBook.d.ts +2 -1
  145. package/dist/types/services/AnswerCallOnWebexService.d.ts +38 -0
  146. package/dist/types/services/ApiAiAssistant.d.ts +56 -5
  147. package/dist/types/services/EntryPoint.d.ts +7 -5
  148. package/dist/types/services/Queue.d.ts +5 -3
  149. package/dist/types/services/UserPreference.d.ts +118 -0
  150. package/dist/types/services/WebexCrossClientService.d.ts +32 -0
  151. package/dist/types/services/WxAppTelephonyMercurySync.d.ts +28 -0
  152. package/dist/types/services/config/constants.d.ts +34 -5
  153. package/dist/types/services/config/types.d.ts +197 -12
  154. package/dist/types/services/core/Err.d.ts +6 -0
  155. package/dist/types/services/core/Utils.d.ts +35 -13
  156. package/dist/types/services/core/WebexRequest.d.ts +1 -0
  157. package/dist/types/services/core/types.d.ts +2 -0
  158. package/dist/types/services/core/websocket/WebSocketManager.d.ts +1 -0
  159. package/dist/types/services/core/websocket/types.d.ts +1 -1
  160. package/dist/types/services/index.d.ts +1 -1
  161. package/dist/types/services/task/Task.d.ts +175 -0
  162. package/dist/types/services/task/TaskFactory.d.ts +13 -0
  163. package/dist/types/services/task/TaskUtils.d.ts +48 -2
  164. package/dist/types/services/task/WebexCallingUtils.d.ts +11 -0
  165. package/dist/types/services/task/constants.d.ts +10 -0
  166. package/dist/types/services/task/contact.d.ts +4 -0
  167. package/dist/types/services/task/dialer.d.ts +30 -0
  168. package/dist/types/services/task/digital/Digital.d.ts +22 -0
  169. package/dist/types/services/task/state-machine/TaskStateMachine.d.ts +1442 -0
  170. package/dist/types/services/task/state-machine/actions.d.ts +10 -0
  171. package/dist/types/services/task/state-machine/constants.d.ts +107 -0
  172. package/dist/types/services/task/state-machine/guards.d.ts +103 -0
  173. package/dist/types/services/task/state-machine/index.d.ts +13 -0
  174. package/dist/types/services/task/state-machine/types.d.ts +277 -0
  175. package/dist/types/services/task/state-machine/uiControlsComputer.d.ts +9 -0
  176. package/dist/types/services/task/taskDataNormalizer.d.ts +10 -0
  177. package/dist/types/services/task/types.d.ts +680 -66
  178. package/dist/types/services/task/voice/Voice.d.ts +227 -0
  179. package/dist/types/services/task/voice/WebRTC.d.ts +53 -0
  180. package/dist/types/services/task/voice/wxAppVoiceMethods.d.ts +55 -0
  181. package/dist/types/services/wxAppDiagnosticLogging.d.ts +51 -0
  182. package/dist/types/services/wxAppTelephonyUtils.d.ts +5 -0
  183. package/dist/types/types.d.ts +205 -9
  184. package/dist/types/utils/PageCache.d.ts +20 -3
  185. package/dist/types/webex.d.ts +1 -0
  186. package/dist/types.js +162 -4
  187. package/dist/types.js.map +1 -1
  188. package/dist/utils/PageCache.js +19 -5
  189. package/dist/utils/PageCache.js.map +1 -1
  190. package/dist/webex.js +22 -2
  191. package/dist/webex.js.map +1 -1
  192. package/package.json +16 -12
  193. package/src/cc.ts +1289 -112
  194. package/src/config.ts +13 -0
  195. package/src/constants.ts +29 -1
  196. package/src/index.ts +36 -5
  197. package/src/metrics/MetricsManager.ts +16 -0
  198. package/src/metrics/ai-docs/AGENTS.md +350 -0
  199. package/src/metrics/ai-docs/ARCHITECTURE.md +338 -0
  200. package/src/metrics/ai-docs/metrics-spec.md +921 -0
  201. package/src/metrics/behavioral-events.ts +212 -0
  202. package/src/metrics/constants.ts +52 -4
  203. package/src/services/AddressBook.ts +17 -6
  204. package/src/services/AnswerCallOnWebexService.ts +239 -0
  205. package/src/services/ApiAiAssistant.ts +356 -9
  206. package/src/services/EntryPoint.ts +59 -60
  207. package/src/services/Queue.ts +29 -12
  208. package/src/services/UserPreference.ts +509 -0
  209. package/src/services/WebexCrossClientService.ts +293 -0
  210. package/src/services/WxAppTelephonyMercurySync.ts +142 -0
  211. package/src/services/agent/ai-docs/AGENTS.md +240 -0
  212. package/src/services/agent/ai-docs/ARCHITECTURE.md +304 -0
  213. package/src/services/agent/ai-docs/agent-spec.md +505 -0
  214. package/src/services/ai-docs/AGENTS.md +386 -0
  215. package/src/services/ai-docs/services-spec.md +505 -0
  216. package/src/services/config/Util.ts +12 -3
  217. package/src/services/config/ai-docs/AGENTS.md +255 -0
  218. package/src/services/config/ai-docs/ARCHITECTURE.md +426 -0
  219. package/src/services/config/ai-docs/config-spec.md +686 -0
  220. package/src/services/config/constants.ts +46 -6
  221. package/src/services/config/index.ts +65 -0
  222. package/src/services/config/types.ts +197 -13
  223. package/src/services/core/Err.ts +3 -0
  224. package/src/services/core/Utils.ts +127 -37
  225. package/src/services/core/WebexRequest.ts +3 -1
  226. package/src/services/core/ai-docs/AGENTS.md +381 -0
  227. package/src/services/core/ai-docs/ARCHITECTURE.md +698 -0
  228. package/src/services/core/ai-docs/core-spec.md +787 -0
  229. package/src/services/core/aqm-reqs.ts +30 -15
  230. package/src/services/core/types.ts +2 -0
  231. package/src/services/core/websocket/WebSocketManager.ts +2 -0
  232. package/src/services/core/websocket/types.ts +1 -1
  233. package/src/services/index.ts +1 -1
  234. package/src/services/task/Task.ts +908 -0
  235. package/src/services/task/TaskFactory.ts +60 -0
  236. package/src/services/task/TaskManager.ts +1419 -608
  237. package/src/services/task/TaskUtils.ts +303 -25
  238. package/src/services/task/WebexCallingUtils.ts +136 -0
  239. package/src/services/task/ai-docs/AGENTS.md +457 -0
  240. package/src/services/task/ai-docs/ARCHITECTURE.md +595 -0
  241. package/src/services/task/ai-docs/task-spec.md +1474 -0
  242. package/src/services/task/constants.ts +10 -0
  243. package/src/services/task/contact.ts +30 -0
  244. package/src/services/task/dialer.ts +80 -0
  245. package/src/services/task/digital/Digital.ts +97 -0
  246. package/src/services/task/state-machine/TaskStateMachine.ts +1320 -0
  247. package/src/services/task/state-machine/actions.ts +741 -0
  248. package/src/services/task/state-machine/ai-docs/AGENTS.md +460 -0
  249. package/src/services/task/state-machine/ai-docs/ARCHITECTURE.md +1156 -0
  250. package/src/services/task/state-machine/ai-docs/task-state-machine-spec.md +2247 -0
  251. package/src/services/task/state-machine/constants.ts +172 -0
  252. package/src/services/task/state-machine/guards.ts +442 -0
  253. package/src/services/task/state-machine/index.ts +28 -0
  254. package/src/services/task/state-machine/types.ts +258 -0
  255. package/src/services/task/state-machine/uiControlsComputer.ts +1135 -0
  256. package/src/services/task/taskDataNormalizer.ts +137 -0
  257. package/src/services/task/types.ts +819 -70
  258. package/src/services/task/voice/Voice.ts +1851 -0
  259. package/src/services/task/voice/WebRTC.ts +191 -0
  260. package/src/services/task/voice/wxAppVoiceMethods.ts +516 -0
  261. package/src/services/wxAppDiagnosticLogging.ts +174 -0
  262. package/src/services/wxAppTelephonyUtils.ts +14 -0
  263. package/src/types.ts +262 -11
  264. package/src/utils/AGENTS.md +289 -0
  265. package/src/utils/PageCache.ts +38 -5
  266. package/src/utils/ai-docs/utils-spec.md +391 -0
  267. package/src/webex.js +10 -0
  268. package/test/unit/spec/cc.ts +2210 -119
  269. package/test/unit/spec/logger-proxy.ts +70 -0
  270. package/test/unit/spec/metrics/MetricsManager.ts +25 -0
  271. package/test/unit/spec/metrics/behavioral-events.ts +60 -0
  272. package/test/unit/spec/services/AddressBook.ts +37 -6
  273. package/test/unit/spec/services/AnswerCallOnWebexService.ts +264 -0
  274. package/test/unit/spec/services/ApiAiAssistant.ts +311 -21
  275. package/test/unit/spec/services/EntryPoint.ts +87 -40
  276. package/test/unit/spec/services/Queue.ts +123 -12
  277. package/test/unit/spec/services/UserPreference.ts +401 -0
  278. package/test/unit/spec/services/WebCallingService.ts +7 -1
  279. package/test/unit/spec/services/WebexCrossClientService.ts +467 -0
  280. package/test/unit/spec/services/WxAppTelephonyMercurySync.ts +136 -0
  281. package/test/unit/spec/services/config/Util.ts +129 -0
  282. package/test/unit/spec/services/config/index.ts +97 -29
  283. package/test/unit/spec/services/core/Utils.ts +425 -8
  284. package/test/unit/spec/services/core/WebexRequest.ts +3 -1
  285. package/test/unit/spec/services/core/aqm-reqs.ts +113 -1
  286. package/test/unit/spec/services/core/websocket/WebSocketManager.ts +66 -40
  287. package/test/unit/spec/services/task/AutoWrapup.ts +63 -0
  288. package/test/unit/spec/services/task/Task.ts +745 -0
  289. package/test/unit/spec/services/task/TaskFactory.ts +99 -0
  290. package/test/unit/spec/services/task/TaskManager.ts +2518 -1494
  291. package/test/unit/spec/services/task/TaskUtils.ts +235 -0
  292. package/test/unit/spec/services/task/WebexCallingUtils.ts +153 -0
  293. package/test/unit/spec/services/task/contact.ts +33 -0
  294. package/test/unit/spec/services/task/dialer.ts +190 -0
  295. package/test/unit/spec/services/task/digital/Digital.ts +105 -0
  296. package/test/unit/spec/services/task/state-machine/TaskStateMachine.ts +4060 -0
  297. package/test/unit/spec/services/task/state-machine/guards.ts +839 -0
  298. package/test/unit/spec/services/task/state-machine/types.ts +18 -0
  299. package/test/unit/spec/services/task/state-machine/uiControlsComputer.ts +3101 -0
  300. package/test/unit/spec/services/task/taskTestUtils.ts +87 -0
  301. package/test/unit/spec/services/task/voice/Voice.ts +2061 -0
  302. package/test/unit/spec/services/task/voice/WebRTC.ts +235 -0
  303. package/test/unit/spec/services/task/voice/wxAppVoiceMethods.ts +603 -0
  304. package/test/unit/spec/services/wxAppDiagnosticLogging.ts +143 -0
  305. package/test/unit/spec/wellnessSampleUtils.ts +288 -0
  306. package/umd/contact-center.min.js +2 -2
  307. package/umd/contact-center.min.js.map +1 -1
  308. package/dist/services/task/index.js +0 -1525
  309. package/dist/services/task/index.js.map +0 -1
  310. package/dist/types/services/task/index.d.ts +0 -650
  311. package/src/services/task/index.ts +0 -1801
  312. package/test/unit/spec/services/task/index.ts +0 -2184
@@ -0,0 +1,191 @@
1
+ import {LocalMicrophoneStream, CALL_EVENT_KEYS} from '@webex/calling';
2
+ import {CC_FILE} from '../../../constants';
3
+ import {getErrorDetails} from '../../core/Utils';
4
+ import routingContact from '../contact';
5
+ import {
6
+ TaskData,
7
+ TaskResponse,
8
+ TASK_EVENTS,
9
+ IWebRTC,
10
+ VoiceUIControlOptions,
11
+ VOICE_VARIANT,
12
+ TaskToggleMuteOptions,
13
+ } from '../types';
14
+ import Voice from './Voice';
15
+ import WebCallingService from '../../WebCallingService';
16
+ import {WrapupData} from '../../config/types';
17
+ import MetricsManager from '../../../metrics/MetricsManager';
18
+ import {METRIC_EVENT_NAMES} from '../../../metrics/constants';
19
+ import LoggerProxy from '../../../logger-proxy';
20
+
21
+ export default class WebRTC extends Voice implements IWebRTC {
22
+ private localAudioStream: LocalMicrophoneStream;
23
+ private webCallingService: WebCallingService;
24
+
25
+ constructor(
26
+ contact: ReturnType<typeof routingContact>,
27
+ webCallingService: WebCallingService,
28
+ data: TaskData,
29
+ callOptions?: VoiceUIControlOptions,
30
+ wrapupData?: WrapupData,
31
+ agentId?: string
32
+ ) {
33
+ const mergedCallOptions: VoiceUIControlOptions = {
34
+ ...callOptions,
35
+ voiceVariant: VOICE_VARIANT.WEBRTC,
36
+ };
37
+
38
+ super(contact, data, mergedCallOptions, wrapupData, agentId);
39
+ this.webCallingService = webCallingService;
40
+ this.registerWebCallListeners();
41
+ }
42
+
43
+ private registerWebCallListeners() {
44
+ this.webCallingService.on(CALL_EVENT_KEYS.REMOTE_MEDIA, this.handleRemoteMedia);
45
+ }
46
+
47
+ private handleRemoteMedia = (track: MediaStreamTrack) => {
48
+ this.emit(TASK_EVENTS.TASK_MEDIA, track);
49
+ };
50
+
51
+ /**
52
+ * This method is used to unregister the web call listeners.
53
+ * @returns void
54
+ * @example
55
+ * ```typescript
56
+ * task.unregisterWebCallListeners();
57
+ * ```
58
+ */
59
+ public unregisterWebCallListeners() {
60
+ this.webCallingService.off(CALL_EVENT_KEYS.REMOTE_MEDIA, this.handleRemoteMedia);
61
+ }
62
+
63
+ /**
64
+ * This is used for incoming task accept by agent.
65
+ *
66
+ * @returns Promise<TaskResponse>
67
+ * @throws Error
68
+ * @example
69
+ * ```typescript
70
+ * task.accept().then(()=>{}).catch(()=>{})
71
+ * ```
72
+ */
73
+ public async accept(): Promise<TaskResponse> {
74
+ LoggerProxy.log(`Accepting WebRTC task for taskId:${this.data.interactionId}`, {
75
+ module: 'WebRTC',
76
+ method: 'accept',
77
+ });
78
+ try {
79
+ this.metricsManager.timeEvent([
80
+ METRIC_EVENT_NAMES.TASK_ACCEPT_SUCCESS,
81
+ METRIC_EVENT_NAMES.TASK_ACCEPT_FAILED,
82
+ ]);
83
+
84
+ const constraints = {audio: true};
85
+ const localStream = await navigator.mediaDevices.getUserMedia(constraints);
86
+ const audioTrack = localStream.getAudioTracks()[0];
87
+ this.localAudioStream = new LocalMicrophoneStream(new MediaStream([audioTrack]));
88
+ this.webCallingService.answerCall(this.localAudioStream, this.data.interactionId);
89
+
90
+ this.metricsManager.trackEvent(
91
+ METRIC_EVENT_NAMES.TASK_ACCEPT_SUCCESS,
92
+ {
93
+ taskId: this.data.interactionId,
94
+ ...MetricsManager.getCommonTrackingFieldForAQMResponse(this.data),
95
+ },
96
+ ['operational', 'behavioral', 'business']
97
+ );
98
+
99
+ return Promise.resolve();
100
+ } catch (error) {
101
+ this.metricsManager.trackEvent(
102
+ METRIC_EVENT_NAMES.TASK_ACCEPT_FAILED,
103
+ {
104
+ taskId: this.data.interactionId,
105
+ error: error.toString(),
106
+ ...MetricsManager.getCommonTrackingFieldForAQMResponseFailed(
107
+ (error as any).details || {}
108
+ ),
109
+ },
110
+ ['operational', 'behavioral', 'business']
111
+ );
112
+ const {error: detailedError} = getErrorDetails(error, 'accept', CC_FILE);
113
+ throw detailedError;
114
+ }
115
+ }
116
+
117
+ /**
118
+ * This is used for the incoming task decline by agent.
119
+ *
120
+ * @returns Promise<TaskResponse>
121
+ * @throws Error
122
+ * @example
123
+ * ```typescript
124
+ * task.decline().then(()=>{}).catch(()=>{})
125
+ * ```
126
+ */
127
+ public async decline(): Promise<TaskResponse> {
128
+ LoggerProxy.log(`Declining WebRTC task for taskId:${this.data.interactionId}`, {
129
+ module: 'WebRTC',
130
+ method: 'decline',
131
+ });
132
+ try {
133
+ this.metricsManager.timeEvent([
134
+ METRIC_EVENT_NAMES.TASK_DECLINE_SUCCESS,
135
+ METRIC_EVENT_NAMES.TASK_DECLINE_FAILED,
136
+ ]);
137
+
138
+ this.webCallingService.declineCall(this.data.interactionId);
139
+ this.unregisterWebCallListeners();
140
+
141
+ this.metricsManager.trackEvent(
142
+ METRIC_EVENT_NAMES.TASK_DECLINE_SUCCESS,
143
+ {taskId: this.data.interactionId},
144
+ ['operational', 'behavioral']
145
+ );
146
+
147
+ return Promise.resolve();
148
+ } catch (error) {
149
+ this.metricsManager.trackEvent(
150
+ METRIC_EVENT_NAMES.TASK_DECLINE_FAILED,
151
+ {
152
+ taskId: this.data.interactionId,
153
+ error: error.toString(),
154
+ ...MetricsManager.getCommonTrackingFieldForAQMResponseFailed(
155
+ (error as any).details || {}
156
+ ),
157
+ },
158
+ ['operational', 'behavioral']
159
+ );
160
+ const {error: detailedError} = getErrorDetails(error, 'decline', CC_FILE);
161
+ throw detailedError;
162
+ }
163
+ }
164
+
165
+ /**
166
+ * This is used for the placing the call in mute or unmute by the agent.
167
+ *
168
+ * @throws Error
169
+ * @example
170
+ * ```typescript
171
+ * task.toggleMute().then(()=>{}).catch(()=>{})
172
+ * ```
173
+ */
174
+ public async toggleMute(options?: TaskToggleMuteOptions) {
175
+ if (options) {
176
+ // parameter intentionally unused — WebRTC toggles from local stream state
177
+ }
178
+ LoggerProxy.log(`Toggling mute WebRTC task for taskId:${this.data.interactionId}`, {
179
+ module: 'WebRTC',
180
+ method: 'toggleMute',
181
+ });
182
+ try {
183
+ this.webCallingService.muteUnmuteCall(this.localAudioStream);
184
+
185
+ return Promise.resolve();
186
+ } catch (error) {
187
+ const {error: detailedError} = getErrorDetails(error, 'mute', CC_FILE);
188
+ throw detailedError;
189
+ }
190
+ }
191
+ }
@@ -0,0 +1,516 @@
1
+ import {EventPayload} from '@webex/internal-plugin-metrics/src/metrics.types';
2
+
3
+ import AnswerCallOnWebexService, {WxAppTelephonyError} from '../../AnswerCallOnWebexService';
4
+ import LoggerProxy from '../../../logger-proxy';
5
+ import {METHODS} from '../../../constants';
6
+ import {getErrorDetails} from '../../core/Utils';
7
+ import {Failure} from '../../core/GlobalTypes';
8
+ import {TaskData, TaskToggleMuteOptions, TaskTransmitDtmfOptions} from '../types';
9
+ import {TaskState} from '../state-machine';
10
+ import MetricsManager from '../../../metrics/MetricsManager';
11
+ import {METRIC_EVENT_NAMES} from '../../../metrics/constants';
12
+ import {
13
+ decodedLineOwnerId,
14
+ getWebexCallingDeviceDetailsForAgent,
15
+ WebexCallingDeviceDetails,
16
+ } from '../WebexCallingUtils';
17
+ import {
18
+ logWxAppTelephonyAction,
19
+ logWxAppValidationFailure,
20
+ type WxAppTelephonyAction,
21
+ } from '../../wxAppDiagnosticLogging';
22
+
23
+ type WxAppParticipant = {
24
+ deviceType?: string;
25
+ deviceCallId?: string;
26
+ deviceId?: string;
27
+ };
28
+
29
+ export type WxAppVoiceDependencies = {
30
+ enableWxBetterTogether: boolean;
31
+ answerCallOnWebexService?: AnswerCallOnWebexService;
32
+ agentId?: string;
33
+ metricsManager: MetricsManager;
34
+ getTaskData: () => TaskData;
35
+ getTaskState: () => TaskState | undefined;
36
+ getWxAppMuted: () => boolean;
37
+ setWxAppMuted: (muted: boolean) => void;
38
+ };
39
+
40
+ /** @deprecated Use {@link WxAppVoiceDependencies} */
41
+ export type WxAppVoiceDeps = WxAppVoiceDependencies;
42
+
43
+ export type WxAppVoiceLifecycle = {
44
+ setWxAppAcceptInFlight: (inFlight: boolean) => void;
45
+ setWxAppAnswerPending: (pending: boolean) => void;
46
+ resetWxAppMuted: () => void;
47
+ syncWxAppMuteFromCallDetails: () => Promise<boolean | undefined>;
48
+ mapWxAppVoiceError: (error: unknown, method: string) => never;
49
+ };
50
+
51
+ const isWxAppParticipant = (participant: unknown): participant is WxAppParticipant =>
52
+ (participant as WxAppParticipant)?.deviceType === 'wxApp' &&
53
+ typeof (participant as WxAppParticipant)?.deviceCallId === 'string' &&
54
+ (participant as WxAppParticipant).deviceCallId.trim() !== '' &&
55
+ typeof (participant as WxAppParticipant)?.deviceId === 'string' &&
56
+ (participant as WxAppParticipant).deviceId.trim() !== '';
57
+
58
+ const isOutdialTask = (deps: WxAppVoiceDependencies): boolean =>
59
+ deps.getTaskData()?.interaction?.outboundType === 'OUTDIAL';
60
+
61
+ function getWxAppAgentParticipant(deps: WxAppVoiceDependencies): unknown {
62
+ const taskData = deps.getTaskData();
63
+ const participants = taskData.interaction?.participants;
64
+ const agentId = deps.agentId ?? taskData.agentId;
65
+
66
+ if (!participants || !agentId) {
67
+ return undefined;
68
+ }
69
+
70
+ if (participants[agentId]) {
71
+ return participants[agentId];
72
+ }
73
+
74
+ return Object.values(participants).find(
75
+ (participant) => (participant as {id?: string})?.id === agentId
76
+ );
77
+ }
78
+
79
+ export function getCallingDeviceDetails(
80
+ deps: WxAppVoiceDependencies
81
+ ): WebexCallingDeviceDetails | undefined {
82
+ const taskData = deps.getTaskData();
83
+ const participant = getWxAppAgentParticipant(deps);
84
+
85
+ if (!isWxAppParticipant(participant)) {
86
+ return undefined;
87
+ }
88
+
89
+ return getWebexCallingDeviceDetailsForAgent(
90
+ deps.agentId ?? taskData.agentId,
91
+ taskData.interaction?.participants
92
+ );
93
+ }
94
+
95
+ export function isWebexAppCallingOffer(deps: WxAppVoiceDependencies): boolean {
96
+ if (!deps.enableWxBetterTogether) {
97
+ return false;
98
+ }
99
+
100
+ const state = deps.getTaskState();
101
+ if (state !== TaskState.OFFERED) {
102
+ return false;
103
+ }
104
+
105
+ const details = getCallingDeviceDetails(deps);
106
+
107
+ return Boolean(details);
108
+ }
109
+
110
+ /** Inbound wxApp offer only — outdial decline uses CC routing, not telephony reject. */
111
+ export function isWebexAppInboundCallingOffer(deps: WxAppVoiceDependencies): boolean {
112
+ return isWebexAppCallingOffer(deps) && !isOutdialTask(deps);
113
+ }
114
+
115
+ export function getWebexCallingCallId(deps: WxAppVoiceDependencies): string | null {
116
+ const state = deps.getTaskState();
117
+ if (
118
+ !state ||
119
+ state === TaskState.OFFERED ||
120
+ state === TaskState.IDLE ||
121
+ state === TaskState.WRAPPING_UP ||
122
+ state === TaskState.TERMINATED ||
123
+ state === TaskState.COMPLETED
124
+ ) {
125
+ return null;
126
+ }
127
+
128
+ return getCallingDeviceDetails(deps)?.deviceCallId ?? null;
129
+ }
130
+
131
+ export function getWxAppLineOwnerId(deps: WxAppVoiceDependencies): string | undefined {
132
+ const participant = getWxAppAgentParticipant(deps) as {lineOwnerId?: string} | undefined;
133
+ const lineOwnerId = participant?.lineOwnerId;
134
+
135
+ return typeof lineOwnerId === 'string' && lineOwnerId.trim() !== '' ? lineOwnerId : undefined;
136
+ }
137
+
138
+ export function resolveWxAppLineOwnerId(
139
+ deps: WxAppVoiceDependencies,
140
+ override?: string
141
+ ): string | undefined {
142
+ if (typeof override === 'string' && override.trim() !== '') {
143
+ return override;
144
+ }
145
+
146
+ return decodedLineOwnerId(getWxAppLineOwnerId(deps));
147
+ }
148
+
149
+ function getInteractionId(deps: WxAppVoiceDependencies): string | undefined {
150
+ return deps.getTaskData()?.interactionId;
151
+ }
152
+
153
+ function logTelephonyFailure(
154
+ action: WxAppTelephonyAction,
155
+ deps: WxAppVoiceDependencies,
156
+ error: unknown
157
+ ): void {
158
+ const wxError = error as WxAppTelephonyError;
159
+ logWxAppTelephonyAction({
160
+ action,
161
+ phase: 'failed',
162
+ interactionId: getInteractionId(deps),
163
+ trackingId: wxError.trackingId,
164
+ httpStatus: wxError.status,
165
+ failureReason: wxError.message,
166
+ });
167
+ }
168
+
169
+ function getWxAppTelephonyMetricFailurePayload(
170
+ deps: WxAppVoiceDependencies,
171
+ error: unknown
172
+ ): Record<string, string> {
173
+ const wxError = error as WxAppTelephonyError;
174
+ const payload: Record<string, string> = {
175
+ taskId: getInteractionId(deps) ?? '',
176
+ error: error instanceof Error ? error.toString() : String(error),
177
+ };
178
+
179
+ if (wxError.trackingId) {
180
+ payload.trackingId = wxError.trackingId;
181
+ }
182
+
183
+ return payload;
184
+ }
185
+
186
+ type AqmWrappedError = {
187
+ details?: Failure;
188
+ };
189
+
190
+ function getWxAppOutdialDeclineFailurePayload(
191
+ deps: WxAppVoiceDependencies,
192
+ error: unknown
193
+ ): EventPayload {
194
+ const base: EventPayload = {
195
+ taskId: getInteractionId(deps) ?? '',
196
+ error: error instanceof Error ? error.toString() : String(error),
197
+ };
198
+ const aqmDetails = (error as AqmWrappedError).details;
199
+
200
+ if (aqmDetails) {
201
+ return {...base, ...MetricsManager.getCommonTrackingFieldForAQMResponseFailed(aqmDetails)};
202
+ }
203
+
204
+ return getWxAppTelephonyMetricFailurePayload(deps, error);
205
+ }
206
+
207
+ function logWxAppOutdialDeclineFailure(deps: WxAppVoiceDependencies, error: unknown): void {
208
+ const aqmDetails = (error as AqmWrappedError).details;
209
+ const wxError = error as WxAppTelephonyError;
210
+
211
+ logWxAppTelephonyAction({
212
+ action: 'decline',
213
+ phase: 'failed',
214
+ interactionId: getInteractionId(deps),
215
+ trackingId: aqmDetails?.trackingId ?? wxError.trackingId,
216
+ httpStatus: wxError.status,
217
+ failureReason: aqmDetails?.data?.reason ?? wxError.message,
218
+ });
219
+ }
220
+
221
+ function assertWxAppEnabled(deps: WxAppVoiceDependencies): void {
222
+ if (!deps.enableWxBetterTogether) {
223
+ logWxAppValidationFailure('enableWxBetterTogether_disabled', getInteractionId(deps));
224
+ throw new Error('enableWxBetterTogether is disabled');
225
+ }
226
+
227
+ if (!deps.answerCallOnWebexService) {
228
+ logWxAppValidationFailure('answer_call_on_webex_service_unavailable', getInteractionId(deps));
229
+ throw new Error('AnswerCallOnWebexService is unavailable');
230
+ }
231
+ }
232
+
233
+ export async function acceptOnWebex(
234
+ deps: WxAppVoiceDependencies,
235
+ options?: {lineOwnerId?: string}
236
+ ): Promise<void> {
237
+ const interactionId = getInteractionId(deps);
238
+ logWxAppTelephonyAction({action: 'accept', phase: 'started', interactionId});
239
+ assertWxAppEnabled(deps);
240
+
241
+ if (!isWebexAppCallingOffer(deps)) {
242
+ logWxAppValidationFailure('not_wxApp_calling_offer', interactionId);
243
+ throw new Error('Task is not a wxApp calling offer');
244
+ }
245
+
246
+ const details = getCallingDeviceDetails(deps);
247
+ if (!details) {
248
+ logWxAppValidationFailure('wxApp_device_details_unavailable', interactionId);
249
+ throw new Error('WxApp calling device details are unavailable');
250
+ }
251
+
252
+ await deps.answerCallOnWebexService.answerCall({
253
+ callId: details.deviceCallId,
254
+ endpointId: details.deviceId,
255
+ lineOwnerId: resolveWxAppLineOwnerId(deps, options?.lineOwnerId),
256
+ });
257
+ logWxAppTelephonyAction({action: 'accept', phase: 'success', interactionId});
258
+ }
259
+
260
+ export async function rejectOnWebex(
261
+ deps: WxAppVoiceDependencies,
262
+ options?: {lineOwnerId?: string}
263
+ ): Promise<void> {
264
+ const interactionId = getInteractionId(deps);
265
+ logWxAppTelephonyAction({action: 'decline', phase: 'started', interactionId});
266
+ assertWxAppEnabled(deps);
267
+
268
+ if (!isWebexAppInboundCallingOffer(deps)) {
269
+ logWxAppValidationFailure('not_wxApp_inbound_calling_offer', interactionId);
270
+ throw new Error('Task is not a wxApp inbound calling offer');
271
+ }
272
+
273
+ const details = getCallingDeviceDetails(deps);
274
+ if (!details) {
275
+ logWxAppValidationFailure('wxApp_device_details_unavailable', interactionId);
276
+ throw new Error('WxApp calling device details are unavailable');
277
+ }
278
+
279
+ await deps.answerCallOnWebexService.rejectCall({
280
+ callId: details.deviceCallId,
281
+ lineOwnerId: resolveWxAppLineOwnerId(deps, options?.lineOwnerId),
282
+ });
283
+ logWxAppTelephonyAction({action: 'decline', phase: 'success', interactionId});
284
+ }
285
+
286
+ export async function toggleMuteOnWebex(
287
+ deps: WxAppVoiceDependencies,
288
+ options?: {lineOwnerId?: string; muted?: boolean}
289
+ ): Promise<void> {
290
+ const interactionId = getInteractionId(deps);
291
+ logWxAppTelephonyAction({action: 'mute', phase: 'started', interactionId});
292
+ assertWxAppEnabled(deps);
293
+
294
+ const callId = getWebexCallingCallId(deps);
295
+ if (!callId) {
296
+ logWxAppValidationFailure('wxApp_call_id_unavailable', interactionId);
297
+ throw new Error('WxApp call ID is unavailable');
298
+ }
299
+
300
+ const targetMuted = options?.muted ?? !deps.getWxAppMuted();
301
+ const request = targetMuted
302
+ ? deps.answerCallOnWebexService.muteCall.bind(deps.answerCallOnWebexService)
303
+ : deps.answerCallOnWebexService.unmuteCall.bind(deps.answerCallOnWebexService);
304
+
305
+ await request({
306
+ callId,
307
+ lineOwnerId: resolveWxAppLineOwnerId(deps, options?.lineOwnerId),
308
+ });
309
+ deps.setWxAppMuted(targetMuted);
310
+ logWxAppTelephonyAction({action: 'mute', phase: 'success', interactionId});
311
+ }
312
+
313
+ export async function transmitDtmfOnWebex(
314
+ deps: WxAppVoiceDependencies,
315
+ options: {dtmf: string; lineOwnerId?: string}
316
+ ): Promise<void> {
317
+ const interactionId = getInteractionId(deps);
318
+ logWxAppTelephonyAction({action: 'dtmf', phase: 'started', interactionId});
319
+ assertWxAppEnabled(deps);
320
+
321
+ const callId = getWebexCallingCallId(deps);
322
+ if (!callId) {
323
+ logWxAppValidationFailure('wxApp_call_id_unavailable', interactionId);
324
+ throw new Error('WxApp call ID is unavailable');
325
+ }
326
+
327
+ LoggerProxy.info('transmitDtmf', {
328
+ module: 'wxAppVoiceMethods',
329
+ method: METHODS.TRANSMIT_DTMF,
330
+ data: {
331
+ interactionId,
332
+ callIdSuffix: callId.length <= 8 ? callId : callId.slice(-8),
333
+ dtmfLength: options.dtmf.length,
334
+ hasLineOwnerId: Boolean(options.lineOwnerId),
335
+ },
336
+ });
337
+
338
+ await deps.answerCallOnWebexService.transmitDtmf({
339
+ callId,
340
+ dtmf: options.dtmf,
341
+ lineOwnerId: resolveWxAppLineOwnerId(deps, options.lineOwnerId),
342
+ });
343
+ logWxAppTelephonyAction({action: 'dtmf', phase: 'success', interactionId});
344
+ }
345
+
346
+ export async function runWxAppAccept(
347
+ deps: WxAppVoiceDependencies,
348
+ lifecycle: WxAppVoiceLifecycle,
349
+ options?: {lineOwnerId?: string}
350
+ ): Promise<void> {
351
+ const taskId = getInteractionId(deps);
352
+
353
+ deps.metricsManager.timeEvent([
354
+ METRIC_EVENT_NAMES.WXAPP_TASK_ACCEPT_SUCCESS,
355
+ METRIC_EVENT_NAMES.WXAPP_TASK_ACCEPT_FAILED,
356
+ ]);
357
+
358
+ try {
359
+ lifecycle.setWxAppAcceptInFlight(true);
360
+ lifecycle.setWxAppAnswerPending(true);
361
+ await acceptOnWebex(deps, options);
362
+ lifecycle.resetWxAppMuted();
363
+ await lifecycle.syncWxAppMuteFromCallDetails();
364
+
365
+ deps.metricsManager.trackEvent(METRIC_EVENT_NAMES.WXAPP_TASK_ACCEPT_SUCCESS, {taskId}, [
366
+ 'operational',
367
+ 'behavioral',
368
+ ]);
369
+ } catch (error) {
370
+ lifecycle.setWxAppAnswerPending(false);
371
+ logTelephonyFailure('accept', deps, error);
372
+ deps.metricsManager.trackEvent(
373
+ METRIC_EVENT_NAMES.WXAPP_TASK_ACCEPT_FAILED,
374
+ getWxAppTelephonyMetricFailurePayload(deps, error),
375
+ ['operational', 'behavioral']
376
+ );
377
+ lifecycle.mapWxAppVoiceError(error, METHODS.ACCEPT);
378
+ } finally {
379
+ lifecycle.setWxAppAcceptInFlight(false);
380
+ }
381
+ }
382
+
383
+ export async function runWxAppReject(
384
+ deps: WxAppVoiceDependencies,
385
+ lifecycle: WxAppVoiceLifecycle,
386
+ options?: {lineOwnerId?: string}
387
+ ): Promise<void> {
388
+ const taskId = getInteractionId(deps);
389
+
390
+ deps.metricsManager.timeEvent([
391
+ METRIC_EVENT_NAMES.WXAPP_TASK_DECLINE_SUCCESS,
392
+ METRIC_EVENT_NAMES.WXAPP_TASK_DECLINE_FAILED,
393
+ ]);
394
+
395
+ try {
396
+ await rejectOnWebex(deps, options);
397
+
398
+ deps.metricsManager.trackEvent(METRIC_EVENT_NAMES.WXAPP_TASK_DECLINE_SUCCESS, {taskId}, [
399
+ 'operational',
400
+ 'behavioral',
401
+ ]);
402
+ } catch (error) {
403
+ logTelephonyFailure('decline', deps, error);
404
+ deps.metricsManager.trackEvent(
405
+ METRIC_EVENT_NAMES.WXAPP_TASK_DECLINE_FAILED,
406
+ getWxAppTelephonyMetricFailurePayload(deps, error),
407
+ ['operational', 'behavioral']
408
+ );
409
+ lifecycle.mapWxAppVoiceError(error, METHODS.REJECT);
410
+ }
411
+ }
412
+
413
+ export async function runWxAppOutdialDecline<T>(
414
+ deps: WxAppVoiceDependencies,
415
+ executeCancel: () => Promise<T>
416
+ ): Promise<T> {
417
+ const taskId = getInteractionId(deps);
418
+
419
+ deps.metricsManager.timeEvent([
420
+ METRIC_EVENT_NAMES.WXAPP_TASK_DECLINE_SUCCESS,
421
+ METRIC_EVENT_NAMES.WXAPP_TASK_DECLINE_FAILED,
422
+ ]);
423
+
424
+ try {
425
+ const result = await executeCancel();
426
+
427
+ deps.metricsManager.trackEvent(METRIC_EVENT_NAMES.WXAPP_TASK_DECLINE_SUCCESS, {taskId}, [
428
+ 'operational',
429
+ 'behavioral',
430
+ ]);
431
+
432
+ return result;
433
+ } catch (error) {
434
+ logWxAppOutdialDeclineFailure(deps, error);
435
+ deps.metricsManager.trackEvent(
436
+ METRIC_EVENT_NAMES.WXAPP_TASK_DECLINE_FAILED,
437
+ getWxAppOutdialDeclineFailurePayload(deps, error),
438
+ ['operational', 'behavioral']
439
+ );
440
+ throw error;
441
+ }
442
+ }
443
+
444
+ export async function runWxAppToggleMute(
445
+ deps: WxAppVoiceDependencies,
446
+ lifecycle: WxAppVoiceLifecycle,
447
+ options?: TaskToggleMuteOptions
448
+ ): Promise<void> {
449
+ const taskId = getInteractionId(deps);
450
+
451
+ deps.metricsManager.timeEvent([
452
+ METRIC_EVENT_NAMES.WXAPP_TASK_MUTE_SUCCESS,
453
+ METRIC_EVENT_NAMES.WXAPP_TASK_MUTE_FAILED,
454
+ ]);
455
+
456
+ try {
457
+ await toggleMuteOnWebex(deps, options);
458
+
459
+ deps.metricsManager.trackEvent(
460
+ METRIC_EVENT_NAMES.WXAPP_TASK_MUTE_SUCCESS,
461
+ {taskId, targetMuted: deps.getWxAppMuted()},
462
+ ['operational', 'behavioral']
463
+ );
464
+ } catch (error) {
465
+ logTelephonyFailure('mute', deps, error);
466
+ deps.metricsManager.trackEvent(
467
+ METRIC_EVENT_NAMES.WXAPP_TASK_MUTE_FAILED,
468
+ getWxAppTelephonyMetricFailurePayload(deps, error),
469
+ ['operational', 'behavioral']
470
+ );
471
+ lifecycle.mapWxAppVoiceError(error, METHODS.TOGGLE_MUTE);
472
+ }
473
+ }
474
+
475
+ export async function runWxAppTransmitDtmf(
476
+ deps: WxAppVoiceDependencies,
477
+ lifecycle: WxAppVoiceLifecycle,
478
+ options: TaskTransmitDtmfOptions
479
+ ): Promise<void> {
480
+ const taskId = getInteractionId(deps);
481
+
482
+ deps.metricsManager.timeEvent([
483
+ METRIC_EVENT_NAMES.WXAPP_TASK_DTMF_SUCCESS,
484
+ METRIC_EVENT_NAMES.WXAPP_TASK_DTMF_FAILED,
485
+ ]);
486
+
487
+ try {
488
+ await transmitDtmfOnWebex(deps, options);
489
+
490
+ deps.metricsManager.trackEvent(
491
+ METRIC_EVENT_NAMES.WXAPP_TASK_DTMF_SUCCESS,
492
+ {taskId, dtmfLength: options.dtmf.length},
493
+ ['operational', 'behavioral']
494
+ );
495
+ } catch (error) {
496
+ logTelephonyFailure('dtmf', deps, error);
497
+ deps.metricsManager.trackEvent(
498
+ METRIC_EVENT_NAMES.WXAPP_TASK_DTMF_FAILED,
499
+ getWxAppTelephonyMetricFailurePayload(deps, error),
500
+ ['operational', 'behavioral']
501
+ );
502
+ lifecycle.mapWxAppVoiceError(error, METHODS.TRANSMIT_DTMF);
503
+ }
504
+ }
505
+
506
+ export function mapWxAppVoiceError(error: unknown, method: string, module: string): never {
507
+ if (
508
+ error instanceof Error &&
509
+ (error as Error & {isWxAppTelephonyError?: boolean}).isWxAppTelephonyError
510
+ ) {
511
+ throw error;
512
+ }
513
+
514
+ const {error: detailedError} = getErrorDetails(error, method, module);
515
+ throw detailedError;
516
+ }