@webex/contact-center 3.12.0-next.15 → 3.12.0-next.151

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 (322) hide show
  1. package/.sdd/manifest.json +887 -0
  2. package/AGENTS.md +94 -0
  3. package/ai-docs/ARCHITECTURE.md +168 -0
  4. package/ai-docs/CONTRACTS.md +62 -0
  5. package/ai-docs/GETTING_STARTED.md +168 -0
  6. package/ai-docs/GLOSSARY.md +43 -0
  7. package/ai-docs/README.md +138 -0
  8. package/ai-docs/REVIEW_CHECKLIST.md +41 -0
  9. package/ai-docs/RULES.md +444 -0
  10. package/ai-docs/SECURITY.md +52 -0
  11. package/ai-docs/SERVICE_STATE.md +52 -0
  12. package/ai-docs/SPEC_INDEX.md +65 -0
  13. package/ai-docs/adr/0001-spec-source-policy.md +55 -0
  14. package/ai-docs/adr/README.md +8 -0
  15. package/ai-docs/adr/_adr-template.md +31 -0
  16. package/ai-docs/contact-center-spec.md +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 +1010 -47
  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 +40 -3
  46. package/dist/constants.js.map +1 -1
  47. package/dist/index.js +54 -17
  48. package/dist/index.js.map +1 -1
  49. package/dist/metrics/MetricsManager.js +16 -0
  50. package/dist/metrics/MetricsManager.js.map +1 -1
  51. package/dist/metrics/behavioral-events.js +211 -0
  52. package/dist/metrics/behavioral-events.js.map +1 -1
  53. package/dist/metrics/constants.js +58 -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 +351 -14
  60. package/dist/services/ApiAiAssistant.js.map +1 -1
  61. package/dist/services/EntryPoint.js +46 -68
  62. package/dist/services/EntryPoint.js.map +1 -1
  63. package/dist/services/Queue.js +27 -22
  64. package/dist/services/Queue.js.map +1 -1
  65. package/dist/services/UserPreference.js +427 -0
  66. package/dist/services/UserPreference.js.map +1 -0
  67. package/dist/services/WebexCrossClientService.js +225 -0
  68. package/dist/services/WebexCrossClientService.js.map +1 -0
  69. package/dist/services/WxAppTelephonyMercurySync.js +111 -0
  70. package/dist/services/WxAppTelephonyMercurySync.js.map +1 -0
  71. package/dist/services/config/Util.js +48 -48
  72. package/dist/services/config/Util.js.map +1 -1
  73. package/dist/services/config/constants.js +56 -78
  74. package/dist/services/config/constants.js.map +1 -1
  75. package/dist/services/config/index.js +100 -226
  76. package/dist/services/config/index.js.map +1 -1
  77. package/dist/services/config/types.js +97 -24
  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 +955 -0
  93. package/dist/services/task/Task.js.map +1 -0
  94. package/dist/services/task/TaskFactory.js +50 -0
  95. package/dist/services/task/TaskFactory.js.map +1 -0
  96. package/dist/services/task/TaskManager.js +1272 -523
  97. package/dist/services/task/TaskManager.js.map +1 -1
  98. package/dist/services/task/TaskUtils.js +221 -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 +21 -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 +259 -5
  127. package/dist/services/task/types.js.map +1 -1
  128. package/dist/services/task/voice/Voice.js +1504 -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/wxAppOfferObservability.js +145 -0
  133. package/dist/services/task/voice/wxAppOfferObservability.js.map +1 -0
  134. package/dist/services/task/voice/wxAppVoiceMethods.js +395 -0
  135. package/dist/services/task/voice/wxAppVoiceMethods.js.map +1 -0
  136. package/dist/services/wxAppDiagnosticLogging.js +159 -0
  137. package/dist/services/wxAppDiagnosticLogging.js.map +1 -0
  138. package/dist/services/wxAppTelephonyUtils.js +19 -0
  139. package/dist/services/wxAppTelephonyUtils.js.map +1 -0
  140. package/dist/types/cc.d.ts +196 -9
  141. package/dist/types/config.d.ts +13 -0
  142. package/dist/types/constants.d.ts +38 -1
  143. package/dist/types/index.d.ts +54 -20
  144. package/dist/types/metrics/MetricsManager.d.ts +6 -0
  145. package/dist/types/metrics/constants.d.ts +52 -1
  146. package/dist/types/services/AddressBook.d.ts +2 -1
  147. package/dist/types/services/AnswerCallOnWebexService.d.ts +38 -0
  148. package/dist/types/services/ApiAiAssistant.d.ts +58 -5
  149. package/dist/types/services/EntryPoint.d.ts +7 -5
  150. package/dist/types/services/Queue.d.ts +5 -3
  151. package/dist/types/services/UserPreference.d.ts +118 -0
  152. package/dist/types/services/WebexCrossClientService.d.ts +32 -0
  153. package/dist/types/services/WxAppTelephonyMercurySync.d.ts +28 -0
  154. package/dist/types/services/config/Util.d.ts +4 -8
  155. package/dist/types/services/config/constants.d.ts +49 -76
  156. package/dist/types/services/config/index.d.ts +16 -64
  157. package/dist/types/services/config/types.d.ts +248 -114
  158. package/dist/types/services/core/Err.d.ts +6 -0
  159. package/dist/types/services/core/Utils.d.ts +35 -13
  160. package/dist/types/services/core/WebexRequest.d.ts +1 -0
  161. package/dist/types/services/core/types.d.ts +2 -0
  162. package/dist/types/services/core/websocket/WebSocketManager.d.ts +1 -0
  163. package/dist/types/services/core/websocket/types.d.ts +1 -1
  164. package/dist/types/services/index.d.ts +1 -1
  165. package/dist/types/services/task/Task.d.ts +186 -0
  166. package/dist/types/services/task/TaskFactory.d.ts +14 -0
  167. package/dist/types/services/task/TaskUtils.d.ts +54 -2
  168. package/dist/types/services/task/WebexCallingUtils.d.ts +11 -0
  169. package/dist/types/services/task/constants.d.ts +19 -0
  170. package/dist/types/services/task/contact.d.ts +4 -0
  171. package/dist/types/services/task/dialer.d.ts +30 -0
  172. package/dist/types/services/task/digital/Digital.d.ts +23 -0
  173. package/dist/types/services/task/state-machine/TaskStateMachine.d.ts +1442 -0
  174. package/dist/types/services/task/state-machine/actions.d.ts +10 -0
  175. package/dist/types/services/task/state-machine/constants.d.ts +107 -0
  176. package/dist/types/services/task/state-machine/guards.d.ts +103 -0
  177. package/dist/types/services/task/state-machine/index.d.ts +13 -0
  178. package/dist/types/services/task/state-machine/types.d.ts +277 -0
  179. package/dist/types/services/task/state-machine/uiControlsComputer.d.ts +9 -0
  180. package/dist/types/services/task/taskDataNormalizer.d.ts +10 -0
  181. package/dist/types/services/task/types.d.ts +790 -66
  182. package/dist/types/services/task/voice/Voice.d.ts +241 -0
  183. package/dist/types/services/task/voice/WebRTC.d.ts +54 -0
  184. package/dist/types/services/task/voice/wxAppOfferObservability.d.ts +39 -0
  185. package/dist/types/services/task/voice/wxAppVoiceMethods.d.ts +68 -0
  186. package/dist/types/services/wxAppDiagnosticLogging.d.ts +63 -0
  187. package/dist/types/services/wxAppTelephonyUtils.d.ts +5 -0
  188. package/dist/types/types.d.ts +213 -11
  189. package/dist/types/utils/PageCache.d.ts +20 -3
  190. package/dist/types/webex.d.ts +1 -0
  191. package/dist/types.js +168 -6
  192. package/dist/types.js.map +1 -1
  193. package/dist/utils/PageCache.js +19 -5
  194. package/dist/utils/PageCache.js.map +1 -1
  195. package/dist/webex.js +22 -2
  196. package/dist/webex.js.map +1 -1
  197. package/package.json +16 -12
  198. package/src/cc.ts +1338 -121
  199. package/src/config.ts +13 -0
  200. package/src/constants.ts +41 -1
  201. package/src/index.ts +62 -15
  202. package/src/metrics/MetricsManager.ts +16 -0
  203. package/src/metrics/ai-docs/AGENTS.md +350 -0
  204. package/src/metrics/ai-docs/ARCHITECTURE.md +338 -0
  205. package/src/metrics/ai-docs/metrics-spec.md +971 -0
  206. package/src/metrics/behavioral-events.ts +218 -0
  207. package/src/metrics/constants.ts +63 -4
  208. package/src/services/AddressBook.ts +17 -6
  209. package/src/services/AnswerCallOnWebexService.ts +239 -0
  210. package/src/services/ApiAiAssistant.ts +470 -15
  211. package/src/services/EntryPoint.ts +59 -60
  212. package/src/services/Queue.ts +29 -12
  213. package/src/services/UserPreference.ts +509 -0
  214. package/src/services/WebexCrossClientService.ts +298 -0
  215. package/src/services/WxAppTelephonyMercurySync.ts +142 -0
  216. package/src/services/agent/ai-docs/AGENTS.md +240 -0
  217. package/src/services/agent/ai-docs/ARCHITECTURE.md +304 -0
  218. package/src/services/agent/ai-docs/agent-spec.md +505 -0
  219. package/src/services/ai-docs/AGENTS.md +386 -0
  220. package/src/services/ai-docs/services-spec.md +505 -0
  221. package/src/services/config/Util.ts +54 -84
  222. package/src/services/config/ai-docs/AGENTS.md +250 -0
  223. package/src/services/config/ai-docs/ARCHITECTURE.md +413 -0
  224. package/src/services/config/ai-docs/config-spec.md +669 -0
  225. package/src/services/config/constants.ts +63 -85
  226. package/src/services/config/index.ts +116 -277
  227. package/src/services/config/types.ts +233 -125
  228. package/src/services/core/Err.ts +3 -0
  229. package/src/services/core/Utils.ts +127 -37
  230. package/src/services/core/WebexRequest.ts +3 -1
  231. package/src/services/core/ai-docs/AGENTS.md +381 -0
  232. package/src/services/core/ai-docs/ARCHITECTURE.md +698 -0
  233. package/src/services/core/ai-docs/core-spec.md +787 -0
  234. package/src/services/core/aqm-reqs.ts +30 -15
  235. package/src/services/core/types.ts +33 -1
  236. package/src/services/core/websocket/WebSocketManager.ts +2 -0
  237. package/src/services/core/websocket/types.ts +1 -1
  238. package/src/services/index.ts +1 -1
  239. package/src/services/task/Task.ts +1211 -0
  240. package/src/services/task/TaskFactory.ts +82 -0
  241. package/src/services/task/TaskManager.ts +1584 -643
  242. package/src/services/task/TaskUtils.ts +316 -25
  243. package/src/services/task/WebexCallingUtils.ts +136 -0
  244. package/src/services/task/ai-docs/AGENTS.md +457 -0
  245. package/src/services/task/ai-docs/ARCHITECTURE.md +595 -0
  246. package/src/services/task/ai-docs/task-spec.md +1501 -0
  247. package/src/services/task/constants.ts +20 -0
  248. package/src/services/task/contact.ts +30 -0
  249. package/src/services/task/dialer.ts +80 -0
  250. package/src/services/task/digital/Digital.ts +102 -0
  251. package/src/services/task/state-machine/TaskStateMachine.ts +1320 -0
  252. package/src/services/task/state-machine/actions.ts +741 -0
  253. package/src/services/task/state-machine/ai-docs/AGENTS.md +460 -0
  254. package/src/services/task/state-machine/ai-docs/ARCHITECTURE.md +1156 -0
  255. package/src/services/task/state-machine/ai-docs/task-state-machine-spec.md +2247 -0
  256. package/src/services/task/state-machine/constants.ts +172 -0
  257. package/src/services/task/state-machine/guards.ts +442 -0
  258. package/src/services/task/state-machine/index.ts +28 -0
  259. package/src/services/task/state-machine/types.ts +258 -0
  260. package/src/services/task/state-machine/uiControlsComputer.ts +1135 -0
  261. package/src/services/task/taskDataNormalizer.ts +137 -0
  262. package/src/services/task/types.ts +974 -70
  263. package/src/services/task/voice/Voice.ts +1878 -0
  264. package/src/services/task/voice/WebRTC.ts +194 -0
  265. package/src/services/task/voice/wxAppOfferObservability.ts +204 -0
  266. package/src/services/task/voice/wxAppVoiceMethods.ts +575 -0
  267. package/src/services/wxAppDiagnosticLogging.ts +286 -0
  268. package/src/services/wxAppTelephonyUtils.ts +14 -0
  269. package/src/types.ts +272 -13
  270. package/src/utils/AGENTS.md +289 -0
  271. package/src/utils/PageCache.ts +38 -5
  272. package/src/utils/ai-docs/utils-spec.md +391 -0
  273. package/src/webex.js +10 -0
  274. package/test/unit/fixtures/aiSummaryTestUtils.ts +40 -0
  275. package/test/unit/spec/cc.ts +3705 -150
  276. package/test/unit/spec/index.ts +885 -0
  277. package/test/unit/spec/logger-proxy.ts +70 -0
  278. package/test/unit/spec/metrics/MetricsManager.ts +25 -0
  279. package/test/unit/spec/metrics/behavioral-events.ts +60 -0
  280. package/test/unit/spec/services/AddressBook.ts +37 -6
  281. package/test/unit/spec/services/AnswerCallOnWebexService.ts +264 -0
  282. package/test/unit/spec/services/ApiAiAssistant.ts +429 -23
  283. package/test/unit/spec/services/EntryPoint.ts +87 -40
  284. package/test/unit/spec/services/Queue.ts +123 -12
  285. package/test/unit/spec/services/UserPreference.ts +401 -0
  286. package/test/unit/spec/services/WebCallingService.ts +7 -1
  287. package/test/unit/spec/services/WebexCrossClientService.ts +509 -0
  288. package/test/unit/spec/services/WxAppTelephonyMercurySync.ts +136 -0
  289. package/test/unit/spec/services/config/Util.ts +501 -0
  290. package/test/unit/spec/services/config/index.ts +317 -547
  291. package/test/unit/spec/services/core/Utils.ts +425 -8
  292. package/test/unit/spec/services/core/WebexRequest.ts +8 -7
  293. package/test/unit/spec/services/core/aqm-reqs.ts +113 -1
  294. package/test/unit/spec/services/core/websocket/WebSocketManager.ts +66 -40
  295. package/test/unit/spec/services/task/AutoWrapup.ts +63 -0
  296. package/test/unit/spec/services/task/Task.ts +2723 -0
  297. package/test/unit/spec/services/task/TaskFactory.ts +116 -0
  298. package/test/unit/spec/services/task/TaskManager.ts +4781 -1585
  299. package/test/unit/spec/services/task/TaskUtils.ts +307 -0
  300. package/test/unit/spec/services/task/WebexCallingUtils.ts +153 -0
  301. package/test/unit/spec/services/task/contact.ts +33 -0
  302. package/test/unit/spec/services/task/dialer.ts +190 -0
  303. package/test/unit/spec/services/task/digital/Digital.ts +105 -0
  304. package/test/unit/spec/services/task/state-machine/TaskStateMachine.ts +4060 -0
  305. package/test/unit/spec/services/task/state-machine/guards.ts +839 -0
  306. package/test/unit/spec/services/task/state-machine/types.ts +18 -0
  307. package/test/unit/spec/services/task/state-machine/uiControlsComputer.ts +3101 -0
  308. package/test/unit/spec/services/task/taskTestUtils.ts +87 -0
  309. package/test/unit/spec/services/task/voice/Voice.ts +2355 -0
  310. package/test/unit/spec/services/task/voice/WebRTC.ts +235 -0
  311. package/test/unit/spec/services/task/voice/wxAppOfferObservability.ts +361 -0
  312. package/test/unit/spec/services/task/voice/wxAppVoiceMethods.ts +719 -0
  313. package/test/unit/spec/services/wxAppDiagnosticLogging.ts +179 -0
  314. package/test/unit/spec/wellnessSampleUtils.ts +288 -0
  315. package/typedoc.md +1 -1
  316. package/umd/contact-center.min.js +2 -2
  317. package/umd/contact-center.min.js.map +1 -1
  318. package/dist/services/task/index.js +0 -1530
  319. package/dist/services/task/index.js.map +0 -1
  320. package/dist/types/services/task/index.d.ts +0 -650
  321. package/src/services/task/index.ts +0 -1806
  322. package/test/unit/spec/services/task/index.ts +0 -2205
@@ -0,0 +1,575 @@
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 WxAppAcceptReason,
21
+ type WxAppTelephonyAction,
22
+ } from '../../wxAppDiagnosticLogging';
23
+
24
+ type WxAppParticipant = {
25
+ deviceType?: string;
26
+ deviceCallId?: string;
27
+ deviceId?: string;
28
+ };
29
+
30
+ export type WxAppVoiceDependencies = {
31
+ enableWxBetterTogether: boolean;
32
+ answerCallOnWebexService?: AnswerCallOnWebexService;
33
+ agentId?: string;
34
+ metricsManager: MetricsManager;
35
+ getTaskData: () => TaskData;
36
+ getTaskState: () => TaskState | undefined;
37
+ getWxAppMuted: () => boolean;
38
+ setWxAppMuted: (muted: boolean) => void;
39
+ /** Read-only observability: whether usersub answer-calls-on-wxcc is active this session. */
40
+ getUsersubPublished?: () => boolean;
41
+ };
42
+
43
+ export type WxAppParticipantDiagnostics = {
44
+ participantDeviceType?: string;
45
+ hasDeviceCallId: boolean;
46
+ hasDeviceId: boolean;
47
+ hasValidWxAppParticipant: boolean;
48
+ };
49
+
50
+ /** @deprecated Use {@link WxAppVoiceDependencies} */
51
+ export type WxAppVoiceDeps = WxAppVoiceDependencies;
52
+
53
+ export type WxAppVoiceLifecycle = {
54
+ setWxAppAcceptInFlight: (inFlight: boolean) => void;
55
+ setWxAppAnswerPending: (pending: boolean) => void;
56
+ resetWxAppMuted: () => void;
57
+ syncWxAppMuteFromCallDetails: () => Promise<boolean | undefined>;
58
+ mapWxAppVoiceError: (error: unknown, method: string) => never;
59
+ };
60
+
61
+ const isWxAppParticipant = (participant: unknown): participant is WxAppParticipant =>
62
+ (participant as WxAppParticipant)?.deviceType === 'wxApp' &&
63
+ typeof (participant as WxAppParticipant)?.deviceCallId === 'string' &&
64
+ (participant as WxAppParticipant).deviceCallId.trim() !== '' &&
65
+ typeof (participant as WxAppParticipant)?.deviceId === 'string' &&
66
+ (participant as WxAppParticipant).deviceId.trim() !== '';
67
+
68
+ const isOutdialTask = (deps: WxAppVoiceDependencies): boolean =>
69
+ deps.getTaskData()?.interaction?.outboundType === 'OUTDIAL';
70
+
71
+ function getWxAppAgentParticipant(deps: WxAppVoiceDependencies): unknown {
72
+ const taskData = deps.getTaskData();
73
+ const participants = taskData.interaction?.participants;
74
+ const agentId = deps.agentId ?? taskData.agentId;
75
+
76
+ if (!participants || !agentId) {
77
+ return undefined;
78
+ }
79
+
80
+ if (participants[agentId]) {
81
+ return participants[agentId];
82
+ }
83
+
84
+ return Object.values(participants).find(
85
+ (participant) => (participant as {id?: string})?.id === agentId
86
+ );
87
+ }
88
+
89
+ export function getWxAppParticipantDiagnostics(
90
+ deps: WxAppVoiceDependencies
91
+ ): WxAppParticipantDiagnostics {
92
+ const participant = getWxAppAgentParticipant(deps) as WxAppParticipant | undefined;
93
+ const hasDeviceCallId =
94
+ typeof participant?.deviceCallId === 'string' && participant.deviceCallId.trim() !== '';
95
+ const hasDeviceId =
96
+ typeof participant?.deviceId === 'string' && participant.deviceId.trim() !== '';
97
+
98
+ return {
99
+ participantDeviceType: participant?.deviceType,
100
+ hasDeviceCallId,
101
+ hasDeviceId,
102
+ hasValidWxAppParticipant: isWxAppParticipant(participant),
103
+ };
104
+ }
105
+
106
+ function getWxAppTelephonyMetricContext(
107
+ deps: WxAppVoiceDependencies
108
+ ): Record<string, boolean | string> {
109
+ const diagnostics = getWxAppParticipantDiagnostics(deps);
110
+
111
+ return {
112
+ hasDeviceCallId: diagnostics.hasDeviceCallId,
113
+ hasDeviceId: diagnostics.hasDeviceId,
114
+ };
115
+ }
116
+
117
+ export function getCallingDeviceDetails(
118
+ deps: WxAppVoiceDependencies
119
+ ): WebexCallingDeviceDetails | undefined {
120
+ const taskData = deps.getTaskData();
121
+ const participant = getWxAppAgentParticipant(deps);
122
+
123
+ if (!isWxAppParticipant(participant)) {
124
+ return undefined;
125
+ }
126
+
127
+ return getWebexCallingDeviceDetailsForAgent(
128
+ deps.agentId ?? taskData.agentId,
129
+ taskData.interaction?.participants
130
+ );
131
+ }
132
+
133
+ export function isWebexAppCallingOffer(deps: WxAppVoiceDependencies): boolean {
134
+ if (!deps.enableWxBetterTogether) {
135
+ return false;
136
+ }
137
+
138
+ const state = deps.getTaskState();
139
+ if (state !== TaskState.OFFERED) {
140
+ return false;
141
+ }
142
+
143
+ const details = getCallingDeviceDetails(deps);
144
+
145
+ return Boolean(details);
146
+ }
147
+
148
+ /** Inbound wxApp offer only — outdial decline uses CC routing, not telephony reject. */
149
+ export function isWebexAppInboundCallingOffer(deps: WxAppVoiceDependencies): boolean {
150
+ return isWebexAppCallingOffer(deps) && !isOutdialTask(deps);
151
+ }
152
+
153
+ export function getWebexCallingCallId(deps: WxAppVoiceDependencies): string | null {
154
+ const state = deps.getTaskState();
155
+ if (
156
+ !state ||
157
+ state === TaskState.OFFERED ||
158
+ state === TaskState.IDLE ||
159
+ state === TaskState.WRAPPING_UP ||
160
+ state === TaskState.TERMINATED ||
161
+ state === TaskState.COMPLETED
162
+ ) {
163
+ return null;
164
+ }
165
+
166
+ return getCallingDeviceDetails(deps)?.deviceCallId ?? null;
167
+ }
168
+
169
+ export function getWxAppLineOwnerId(deps: WxAppVoiceDependencies): string | undefined {
170
+ const participant = getWxAppAgentParticipant(deps) as {lineOwnerId?: string} | undefined;
171
+ const lineOwnerId = participant?.lineOwnerId;
172
+
173
+ return typeof lineOwnerId === 'string' && lineOwnerId.trim() !== '' ? lineOwnerId : undefined;
174
+ }
175
+
176
+ export function resolveWxAppLineOwnerId(
177
+ deps: WxAppVoiceDependencies,
178
+ override?: string
179
+ ): string | undefined {
180
+ if (typeof override === 'string' && override.trim() !== '') {
181
+ return override;
182
+ }
183
+
184
+ return decodedLineOwnerId(getWxAppLineOwnerId(deps));
185
+ }
186
+
187
+ function getInteractionId(deps: WxAppVoiceDependencies): string | undefined {
188
+ return deps.getTaskData()?.interactionId;
189
+ }
190
+
191
+ function logTelephonyFailure(
192
+ action: WxAppTelephonyAction,
193
+ deps: WxAppVoiceDependencies,
194
+ error: unknown
195
+ ): void {
196
+ const wxError = error as WxAppTelephonyError;
197
+ logWxAppTelephonyAction({
198
+ action,
199
+ phase: 'failed',
200
+ interactionId: getInteractionId(deps),
201
+ trackingId: wxError.trackingId,
202
+ httpStatus: wxError.status,
203
+ failureReason: wxError.message,
204
+ });
205
+ }
206
+
207
+ function getWxAppTelephonyMetricFailurePayload(
208
+ deps: WxAppVoiceDependencies,
209
+ error: unknown
210
+ ): Record<string, string | boolean> {
211
+ const wxError = error as WxAppTelephonyError;
212
+ const payload: Record<string, string | boolean> = {
213
+ taskId: getInteractionId(deps) ?? '',
214
+ error: error instanceof Error ? error.toString() : String(error),
215
+ ...getWxAppTelephonyMetricContext(deps),
216
+ };
217
+
218
+ if (wxError.trackingId) {
219
+ payload.trackingId = wxError.trackingId;
220
+ }
221
+
222
+ return payload;
223
+ }
224
+
225
+ type AqmWrappedError = {
226
+ details?: Failure;
227
+ };
228
+
229
+ function getWxAppOutdialDeclineFailurePayload(
230
+ deps: WxAppVoiceDependencies,
231
+ error: unknown
232
+ ): EventPayload {
233
+ const base: EventPayload = {
234
+ taskId: getInteractionId(deps) ?? '',
235
+ error: error instanceof Error ? error.toString() : String(error),
236
+ };
237
+ const aqmDetails = (error as AqmWrappedError).details;
238
+
239
+ if (aqmDetails) {
240
+ return {
241
+ ...base,
242
+ ...getWxAppTelephonyMetricContext(deps),
243
+ ...MetricsManager.getCommonTrackingFieldForAQMResponseFailed(aqmDetails),
244
+ };
245
+ }
246
+
247
+ return getWxAppTelephonyMetricFailurePayload(deps, error);
248
+ }
249
+
250
+ function logWxAppOutdialDeclineFailure(deps: WxAppVoiceDependencies, error: unknown): void {
251
+ const aqmDetails = (error as AqmWrappedError).details;
252
+ const wxError = error as WxAppTelephonyError;
253
+
254
+ logWxAppTelephonyAction({
255
+ action: 'decline',
256
+ phase: 'failed',
257
+ interactionId: getInteractionId(deps),
258
+ trackingId: aqmDetails?.trackingId ?? wxError.trackingId,
259
+ httpStatus: wxError.status,
260
+ failureReason: aqmDetails?.data?.reason ?? wxError.message,
261
+ });
262
+ }
263
+
264
+ function assertWxAppEnabled(deps: WxAppVoiceDependencies): void {
265
+ if (!deps.enableWxBetterTogether) {
266
+ logWxAppValidationFailure('enableWxBetterTogether_disabled', getInteractionId(deps));
267
+ throw new Error('enableWxBetterTogether is disabled');
268
+ }
269
+
270
+ if (!deps.answerCallOnWebexService) {
271
+ logWxAppValidationFailure('answer_call_on_webex_service_unavailable', getInteractionId(deps));
272
+ throw new Error('AnswerCallOnWebexService is unavailable');
273
+ }
274
+ }
275
+
276
+ export async function acceptOnWebex(
277
+ deps: WxAppVoiceDependencies,
278
+ options?: {lineOwnerId?: string}
279
+ ): Promise<void> {
280
+ const interactionId = getInteractionId(deps);
281
+ logWxAppTelephonyAction({action: 'accept', phase: 'started', interactionId});
282
+ assertWxAppEnabled(deps);
283
+
284
+ if (!isWebexAppCallingOffer(deps)) {
285
+ logWxAppValidationFailure('not_wxApp_calling_offer', interactionId);
286
+ throw new Error('Task is not a wxApp calling offer');
287
+ }
288
+
289
+ const details = getCallingDeviceDetails(deps);
290
+ if (!details) {
291
+ logWxAppValidationFailure('wxApp_device_details_unavailable', interactionId);
292
+ throw new Error('WxApp calling device details are unavailable');
293
+ }
294
+
295
+ await deps.answerCallOnWebexService.answerCall({
296
+ callId: details.deviceCallId,
297
+ endpointId: details.deviceId,
298
+ lineOwnerId: resolveWxAppLineOwnerId(deps, options?.lineOwnerId),
299
+ });
300
+ logWxAppTelephonyAction({action: 'accept', phase: 'success', interactionId});
301
+ }
302
+
303
+ export async function rejectOnWebex(
304
+ deps: WxAppVoiceDependencies,
305
+ options?: {lineOwnerId?: string}
306
+ ): Promise<void> {
307
+ const interactionId = getInteractionId(deps);
308
+ logWxAppTelephonyAction({action: 'decline', phase: 'started', interactionId});
309
+ assertWxAppEnabled(deps);
310
+
311
+ if (!isWebexAppInboundCallingOffer(deps)) {
312
+ logWxAppValidationFailure('not_wxApp_inbound_calling_offer', interactionId);
313
+ throw new Error('Task is not a wxApp inbound calling offer');
314
+ }
315
+
316
+ const details = getCallingDeviceDetails(deps);
317
+ if (!details) {
318
+ logWxAppValidationFailure('wxApp_device_details_unavailable', interactionId);
319
+ throw new Error('WxApp calling device details are unavailable');
320
+ }
321
+
322
+ await deps.answerCallOnWebexService.rejectCall({
323
+ callId: details.deviceCallId,
324
+ lineOwnerId: resolveWxAppLineOwnerId(deps, options?.lineOwnerId),
325
+ });
326
+ logWxAppTelephonyAction({action: 'decline', phase: 'success', interactionId});
327
+ }
328
+
329
+ export async function toggleMuteOnWebex(
330
+ deps: WxAppVoiceDependencies,
331
+ options?: {lineOwnerId?: string; muted?: boolean}
332
+ ): Promise<void> {
333
+ const interactionId = getInteractionId(deps);
334
+ logWxAppTelephonyAction({action: 'mute', phase: 'started', interactionId});
335
+ assertWxAppEnabled(deps);
336
+
337
+ const callId = getWebexCallingCallId(deps);
338
+ if (!callId) {
339
+ logWxAppValidationFailure('wxApp_call_id_unavailable', interactionId);
340
+ throw new Error('WxApp call ID is unavailable');
341
+ }
342
+
343
+ const targetMuted = options?.muted ?? !deps.getWxAppMuted();
344
+ const request = targetMuted
345
+ ? deps.answerCallOnWebexService.muteCall.bind(deps.answerCallOnWebexService)
346
+ : deps.answerCallOnWebexService.unmuteCall.bind(deps.answerCallOnWebexService);
347
+
348
+ await request({
349
+ callId,
350
+ lineOwnerId: resolveWxAppLineOwnerId(deps, options?.lineOwnerId),
351
+ });
352
+ deps.setWxAppMuted(targetMuted);
353
+ logWxAppTelephonyAction({action: 'mute', phase: 'success', interactionId});
354
+ }
355
+
356
+ export async function transmitDtmfOnWebex(
357
+ deps: WxAppVoiceDependencies,
358
+ options: {dtmf: string; lineOwnerId?: string}
359
+ ): Promise<void> {
360
+ const interactionId = getInteractionId(deps);
361
+ logWxAppTelephonyAction({action: 'dtmf', phase: 'started', interactionId});
362
+ assertWxAppEnabled(deps);
363
+
364
+ const callId = getWebexCallingCallId(deps);
365
+ if (!callId) {
366
+ logWxAppValidationFailure('wxApp_call_id_unavailable', interactionId);
367
+ throw new Error('WxApp call ID is unavailable');
368
+ }
369
+
370
+ LoggerProxy.log('transmitDtmf', {
371
+ module: 'wxAppVoiceMethods',
372
+ method: METHODS.TRANSMIT_DTMF,
373
+ data: {
374
+ interactionId,
375
+ callIdSuffix: callId.length <= 8 ? callId : callId.slice(-8),
376
+ dtmfLength: options.dtmf.length,
377
+ hasLineOwnerId: Boolean(options.lineOwnerId),
378
+ },
379
+ });
380
+
381
+ await deps.answerCallOnWebexService.transmitDtmf({
382
+ callId,
383
+ dtmf: options.dtmf,
384
+ lineOwnerId: resolveWxAppLineOwnerId(deps, options.lineOwnerId),
385
+ });
386
+ logWxAppTelephonyAction({action: 'dtmf', phase: 'success', interactionId});
387
+ }
388
+
389
+ export type WxAppAcceptRejectOptions = {
390
+ lineOwnerId?: string;
391
+ acceptReason?: WxAppAcceptReason;
392
+ };
393
+
394
+ export async function runWxAppAccept(
395
+ deps: WxAppVoiceDependencies,
396
+ lifecycle: WxAppVoiceLifecycle,
397
+ options?: WxAppAcceptRejectOptions
398
+ ): Promise<void> {
399
+ const taskId = getInteractionId(deps);
400
+ const acceptReason = options?.acceptReason ?? 'wxApp_offer_ready';
401
+
402
+ deps.metricsManager.timeEvent([
403
+ METRIC_EVENT_NAMES.WXAPP_TASK_ACCEPT_SUCCESS,
404
+ METRIC_EVENT_NAMES.WXAPP_TASK_ACCEPT_FAILED,
405
+ ]);
406
+
407
+ try {
408
+ lifecycle.setWxAppAcceptInFlight(true);
409
+ lifecycle.setWxAppAnswerPending(true);
410
+ await acceptOnWebex(deps, options);
411
+ lifecycle.resetWxAppMuted();
412
+ await lifecycle.syncWxAppMuteFromCallDetails();
413
+
414
+ deps.metricsManager.trackEvent(
415
+ METRIC_EVENT_NAMES.WXAPP_TASK_ACCEPT_SUCCESS,
416
+ {taskId, acceptReason, ...getWxAppTelephonyMetricContext(deps)},
417
+ ['operational', 'behavioral']
418
+ );
419
+ } catch (error) {
420
+ lifecycle.setWxAppAnswerPending(false);
421
+ logTelephonyFailure('accept', deps, error);
422
+ deps.metricsManager.trackEvent(
423
+ METRIC_EVENT_NAMES.WXAPP_TASK_ACCEPT_FAILED,
424
+ {acceptReason, ...getWxAppTelephonyMetricFailurePayload(deps, error)},
425
+ ['operational', 'behavioral']
426
+ );
427
+ lifecycle.mapWxAppVoiceError(error, METHODS.ACCEPT);
428
+ } finally {
429
+ lifecycle.setWxAppAcceptInFlight(false);
430
+ }
431
+ }
432
+
433
+ export async function runWxAppReject(
434
+ deps: WxAppVoiceDependencies,
435
+ lifecycle: WxAppVoiceLifecycle,
436
+ options?: WxAppAcceptRejectOptions
437
+ ): Promise<void> {
438
+ const taskId = getInteractionId(deps);
439
+ const acceptReason = options?.acceptReason ?? 'wxApp_offer_ready';
440
+
441
+ deps.metricsManager.timeEvent([
442
+ METRIC_EVENT_NAMES.WXAPP_TASK_DECLINE_SUCCESS,
443
+ METRIC_EVENT_NAMES.WXAPP_TASK_DECLINE_FAILED,
444
+ ]);
445
+
446
+ try {
447
+ await rejectOnWebex(deps, options);
448
+
449
+ deps.metricsManager.trackEvent(
450
+ METRIC_EVENT_NAMES.WXAPP_TASK_DECLINE_SUCCESS,
451
+ {taskId, acceptReason, ...getWxAppTelephonyMetricContext(deps)},
452
+ ['operational', 'behavioral']
453
+ );
454
+ } catch (error) {
455
+ logTelephonyFailure('decline', deps, error);
456
+ deps.metricsManager.trackEvent(
457
+ METRIC_EVENT_NAMES.WXAPP_TASK_DECLINE_FAILED,
458
+ {acceptReason, ...getWxAppTelephonyMetricFailurePayload(deps, error)},
459
+ ['operational', 'behavioral']
460
+ );
461
+ lifecycle.mapWxAppVoiceError(error, METHODS.REJECT);
462
+ }
463
+ }
464
+
465
+ export type WxAppOutdialDeclineOptions = {
466
+ acceptReason?: WxAppAcceptReason;
467
+ };
468
+
469
+ export async function runWxAppOutdialDecline<T>(
470
+ deps: WxAppVoiceDependencies,
471
+ executeCancel: () => Promise<T>,
472
+ options?: WxAppOutdialDeclineOptions
473
+ ): Promise<T> {
474
+ const taskId = getInteractionId(deps);
475
+ const acceptReason = options?.acceptReason ?? 'wxApp_offer_ready';
476
+
477
+ deps.metricsManager.timeEvent([
478
+ METRIC_EVENT_NAMES.WXAPP_TASK_DECLINE_SUCCESS,
479
+ METRIC_EVENT_NAMES.WXAPP_TASK_DECLINE_FAILED,
480
+ ]);
481
+
482
+ try {
483
+ const result = await executeCancel();
484
+
485
+ deps.metricsManager.trackEvent(
486
+ METRIC_EVENT_NAMES.WXAPP_TASK_DECLINE_SUCCESS,
487
+ {taskId, acceptReason, ...getWxAppTelephonyMetricContext(deps)},
488
+ ['operational', 'behavioral']
489
+ );
490
+
491
+ return result;
492
+ } catch (error) {
493
+ logWxAppOutdialDeclineFailure(deps, error);
494
+ deps.metricsManager.trackEvent(
495
+ METRIC_EVENT_NAMES.WXAPP_TASK_DECLINE_FAILED,
496
+ {acceptReason, ...getWxAppOutdialDeclineFailurePayload(deps, error)},
497
+ ['operational', 'behavioral']
498
+ );
499
+ throw error;
500
+ }
501
+ }
502
+
503
+ export async function runWxAppToggleMute(
504
+ deps: WxAppVoiceDependencies,
505
+ lifecycle: WxAppVoiceLifecycle,
506
+ options?: TaskToggleMuteOptions
507
+ ): Promise<void> {
508
+ const taskId = getInteractionId(deps);
509
+
510
+ deps.metricsManager.timeEvent([
511
+ METRIC_EVENT_NAMES.WXAPP_TASK_MUTE_SUCCESS,
512
+ METRIC_EVENT_NAMES.WXAPP_TASK_MUTE_FAILED,
513
+ ]);
514
+
515
+ try {
516
+ await toggleMuteOnWebex(deps, options);
517
+
518
+ deps.metricsManager.trackEvent(
519
+ METRIC_EVENT_NAMES.WXAPP_TASK_MUTE_SUCCESS,
520
+ {taskId, targetMuted: deps.getWxAppMuted(), ...getWxAppTelephonyMetricContext(deps)},
521
+ ['operational', 'behavioral']
522
+ );
523
+ } catch (error) {
524
+ logTelephonyFailure('mute', deps, error);
525
+ deps.metricsManager.trackEvent(
526
+ METRIC_EVENT_NAMES.WXAPP_TASK_MUTE_FAILED,
527
+ getWxAppTelephonyMetricFailurePayload(deps, error),
528
+ ['operational', 'behavioral']
529
+ );
530
+ lifecycle.mapWxAppVoiceError(error, METHODS.TOGGLE_MUTE);
531
+ }
532
+ }
533
+
534
+ export async function runWxAppTransmitDtmf(
535
+ deps: WxAppVoiceDependencies,
536
+ lifecycle: WxAppVoiceLifecycle,
537
+ options: TaskTransmitDtmfOptions
538
+ ): Promise<void> {
539
+ const taskId = getInteractionId(deps);
540
+
541
+ deps.metricsManager.timeEvent([
542
+ METRIC_EVENT_NAMES.WXAPP_TASK_DTMF_SUCCESS,
543
+ METRIC_EVENT_NAMES.WXAPP_TASK_DTMF_FAILED,
544
+ ]);
545
+
546
+ try {
547
+ await transmitDtmfOnWebex(deps, options);
548
+
549
+ deps.metricsManager.trackEvent(
550
+ METRIC_EVENT_NAMES.WXAPP_TASK_DTMF_SUCCESS,
551
+ {taskId, dtmfLength: options.dtmf.length, ...getWxAppTelephonyMetricContext(deps)},
552
+ ['operational', 'behavioral']
553
+ );
554
+ } catch (error) {
555
+ logTelephonyFailure('dtmf', deps, error);
556
+ deps.metricsManager.trackEvent(
557
+ METRIC_EVENT_NAMES.WXAPP_TASK_DTMF_FAILED,
558
+ getWxAppTelephonyMetricFailurePayload(deps, error),
559
+ ['operational', 'behavioral']
560
+ );
561
+ lifecycle.mapWxAppVoiceError(error, METHODS.TRANSMIT_DTMF);
562
+ }
563
+ }
564
+
565
+ export function mapWxAppVoiceError(error: unknown, method: string, module: string): never {
566
+ if (
567
+ error instanceof Error &&
568
+ (error as Error & {isWxAppTelephonyError?: boolean}).isWxAppTelephonyError
569
+ ) {
570
+ throw error;
571
+ }
572
+
573
+ const {error: detailedError} = getErrorDetails(error, method, module);
574
+ throw detailedError;
575
+ }