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

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (328) hide show
  1. package/.sdd/manifest.json +887 -0
  2. package/AGENTS.md +94 -0
  3. package/ai-docs/ARCHITECTURE.md +168 -0
  4. package/ai-docs/CONTRACTS.md +62 -0
  5. package/ai-docs/GETTING_STARTED.md +168 -0
  6. package/ai-docs/GLOSSARY.md +43 -0
  7. package/ai-docs/README.md +138 -0
  8. package/ai-docs/REVIEW_CHECKLIST.md +41 -0
  9. package/ai-docs/RULES.md +444 -0
  10. package/ai-docs/SECURITY.md +52 -0
  11. package/ai-docs/SERVICE_STATE.md +52 -0
  12. package/ai-docs/SPEC_INDEX.md +65 -0
  13. package/ai-docs/adr/0001-spec-source-policy.md +55 -0
  14. package/ai-docs/adr/README.md +8 -0
  15. package/ai-docs/adr/_adr-template.md +31 -0
  16. package/ai-docs/contact-center-spec.md +385 -0
  17. package/ai-docs/features/consult-transfer-list-policy/spec/feature-spec.md +362 -0
  18. package/ai-docs/features/contact-owner-change-refactor.md +78 -0
  19. package/ai-docs/features/generated-spec-conformance-fidelity-remediation/spec/feature-spec.md +117 -0
  20. package/ai-docs/features/residual-warning-coverage-completion/spec/feature-spec.md +203 -0
  21. package/ai-docs/features/validator-code-fidelity-drift-fix/spec/feature-spec.md +315 -0
  22. package/ai-docs/patterns/event-driven-patterns.md +485 -0
  23. package/ai-docs/patterns/testing-patterns.md +480 -0
  24. package/ai-docs/patterns/typescript-patterns.md +365 -0
  25. package/ai-docs/templates/README.md +102 -0
  26. package/ai-docs/templates/documentation/create-agents-md.md +240 -0
  27. package/ai-docs/templates/documentation/create-architecture-md.md +295 -0
  28. package/ai-docs/templates/existing-service/bug-fix.md +254 -0
  29. package/ai-docs/templates/existing-service/feature-enhancement.md +450 -0
  30. package/ai-docs/templates/new-method/00-master.md +80 -0
  31. package/ai-docs/templates/new-method/01-requirements.md +232 -0
  32. package/ai-docs/templates/new-method/02-implementation.md +295 -0
  33. package/ai-docs/templates/new-method/03-tests.md +201 -0
  34. package/ai-docs/templates/new-method/04-validation.md +141 -0
  35. package/ai-docs/templates/new-service/00-master.md +109 -0
  36. package/ai-docs/templates/new-service/01-pre-questions.md +159 -0
  37. package/ai-docs/templates/new-service/02-code-generation.md +346 -0
  38. package/ai-docs/templates/new-service/03-integration.md +178 -0
  39. package/ai-docs/templates/new-service/04-test-generation.md +205 -0
  40. package/ai-docs/templates/new-service/05-validation.md +145 -0
  41. package/dist/cc.js +888 -49
  42. package/dist/cc.js.map +1 -1
  43. package/dist/config.js +13 -0
  44. package/dist/config.js.map +1 -1
  45. package/dist/constants.js +38 -3
  46. package/dist/constants.js.map +1 -1
  47. package/dist/index.js +54 -17
  48. package/dist/index.js.map +1 -1
  49. package/dist/metrics/MetricsManager.js +16 -0
  50. package/dist/metrics/MetricsManager.js.map +1 -1
  51. package/dist/metrics/behavioral-events.js +185 -0
  52. package/dist/metrics/behavioral-events.js.map +1 -1
  53. package/dist/metrics/constants.js +54 -4
  54. package/dist/metrics/constants.js.map +1 -1
  55. package/dist/services/AddressBook.js +18 -15
  56. package/dist/services/AddressBook.js.map +1 -1
  57. package/dist/services/AnswerCallOnWebexService.js +202 -0
  58. package/dist/services/AnswerCallOnWebexService.js.map +1 -0
  59. package/dist/services/ApiAiAssistant.js +369 -14
  60. package/dist/services/ApiAiAssistant.js.map +1 -1
  61. package/dist/services/EntryPoint.js +46 -68
  62. package/dist/services/EntryPoint.js.map +1 -1
  63. package/dist/services/Queue.js +27 -22
  64. package/dist/services/Queue.js.map +1 -1
  65. package/dist/services/UserPreference.js +427 -0
  66. package/dist/services/UserPreference.js.map +1 -0
  67. package/dist/services/WebCallingService.js +10 -2
  68. package/dist/services/WebCallingService.js.map +1 -1
  69. package/dist/services/WebexCrossClientService.js +225 -0
  70. package/dist/services/WebexCrossClientService.js.map +1 -0
  71. package/dist/services/WxAppTelephonyMercurySync.js +111 -0
  72. package/dist/services/WxAppTelephonyMercurySync.js.map +1 -0
  73. package/dist/services/config/Util.js +48 -48
  74. package/dist/services/config/Util.js.map +1 -1
  75. package/dist/services/config/constants.js +56 -78
  76. package/dist/services/config/constants.js.map +1 -1
  77. package/dist/services/config/index.js +100 -226
  78. package/dist/services/config/index.js.map +1 -1
  79. package/dist/services/config/types.js +93 -24
  80. package/dist/services/config/types.js.map +1 -1
  81. package/dist/services/constants.js +11 -1
  82. package/dist/services/constants.js.map +1 -1
  83. package/dist/services/core/Err.js.map +1 -1
  84. package/dist/services/core/Utils.js +131 -32
  85. package/dist/services/core/Utils.js.map +1 -1
  86. package/dist/services/core/WebexRequest.js +6 -2
  87. package/dist/services/core/WebexRequest.js.map +1 -1
  88. package/dist/services/core/aqm-reqs.js +17 -11
  89. package/dist/services/core/aqm-reqs.js.map +1 -1
  90. package/dist/services/core/constants.js +9 -1
  91. package/dist/services/core/constants.js.map +1 -1
  92. package/dist/services/core/types.js.map +1 -1
  93. package/dist/services/core/websocket/WebSocketManager.js +19 -2
  94. package/dist/services/core/websocket/WebSocketManager.js.map +1 -1
  95. package/dist/services/core/websocket/types.js.map +1 -1
  96. package/dist/services/index.js +1 -1
  97. package/dist/services/index.js.map +1 -1
  98. package/dist/services/task/Task.js +955 -0
  99. package/dist/services/task/Task.js.map +1 -0
  100. package/dist/services/task/TaskFactory.js +50 -0
  101. package/dist/services/task/TaskFactory.js.map +1 -0
  102. package/dist/services/task/TaskManager.js +1272 -605
  103. package/dist/services/task/TaskManager.js.map +1 -1
  104. package/dist/services/task/TaskUtils.js +221 -27
  105. package/dist/services/task/TaskUtils.js.map +1 -1
  106. package/dist/services/task/WebexCallingUtils.js +70 -0
  107. package/dist/services/task/WebexCallingUtils.js.map +1 -0
  108. package/dist/services/task/constants.js +19 -2
  109. package/dist/services/task/constants.js.map +1 -1
  110. package/dist/services/task/contact.js +29 -0
  111. package/dist/services/task/contact.js.map +1 -1
  112. package/dist/services/task/digital/Digital.js +78 -0
  113. package/dist/services/task/digital/Digital.js.map +1 -0
  114. package/dist/services/task/state-machine/TaskStateMachine.js +982 -0
  115. package/dist/services/task/state-machine/TaskStateMachine.js.map +1 -0
  116. package/dist/services/task/state-machine/actions.js +572 -0
  117. package/dist/services/task/state-machine/actions.js.map +1 -0
  118. package/dist/services/task/state-machine/constants.js +161 -0
  119. package/dist/services/task/state-machine/constants.js.map +1 -0
  120. package/dist/services/task/state-machine/guards.js +379 -0
  121. package/dist/services/task/state-machine/guards.js.map +1 -0
  122. package/dist/services/task/state-machine/index.js +53 -0
  123. package/dist/services/task/state-machine/index.js.map +1 -0
  124. package/dist/services/task/state-machine/types.js +54 -0
  125. package/dist/services/task/state-machine/types.js.map +1 -0
  126. package/dist/services/task/state-machine/uiControlsComputer.js +703 -0
  127. package/dist/services/task/state-machine/uiControlsComputer.js.map +1 -0
  128. package/dist/services/task/taskDataNormalizer.js +99 -0
  129. package/dist/services/task/taskDataNormalizer.js.map +1 -0
  130. package/dist/services/task/types.js +215 -5
  131. package/dist/services/task/types.js.map +1 -1
  132. package/dist/services/task/voice/Voice.js +1504 -0
  133. package/dist/services/task/voice/Voice.js.map +1 -0
  134. package/dist/services/task/voice/WebRTC.js +152 -0
  135. package/dist/services/task/voice/WebRTC.js.map +1 -0
  136. package/dist/services/task/voice/wxAppOfferObservability.js +145 -0
  137. package/dist/services/task/voice/wxAppOfferObservability.js.map +1 -0
  138. package/dist/services/task/voice/wxAppVoiceMethods.js +395 -0
  139. package/dist/services/task/voice/wxAppVoiceMethods.js.map +1 -0
  140. package/dist/services/wxAppDiagnosticLogging.js +159 -0
  141. package/dist/services/wxAppDiagnosticLogging.js.map +1 -0
  142. package/dist/services/wxAppTelephonyUtils.js +19 -0
  143. package/dist/services/wxAppTelephonyUtils.js.map +1 -0
  144. package/dist/types/cc.d.ts +152 -9
  145. package/dist/types/config.d.ts +13 -0
  146. package/dist/types/constants.d.ts +36 -1
  147. package/dist/types/index.d.ts +54 -20
  148. package/dist/types/metrics/MetricsManager.d.ts +6 -0
  149. package/dist/types/metrics/constants.d.ts +48 -1
  150. package/dist/types/services/AddressBook.d.ts +2 -1
  151. package/dist/types/services/AnswerCallOnWebexService.d.ts +38 -0
  152. package/dist/types/services/ApiAiAssistant.d.ts +67 -5
  153. package/dist/types/services/EntryPoint.d.ts +7 -5
  154. package/dist/types/services/Queue.d.ts +5 -3
  155. package/dist/types/services/UserPreference.d.ts +118 -0
  156. package/dist/types/services/WebexCrossClientService.d.ts +32 -0
  157. package/dist/types/services/WxAppTelephonyMercurySync.d.ts +28 -0
  158. package/dist/types/services/config/Util.d.ts +4 -8
  159. package/dist/types/services/config/constants.d.ts +49 -76
  160. package/dist/types/services/config/index.d.ts +16 -64
  161. package/dist/types/services/config/types.d.ts +240 -114
  162. package/dist/types/services/constants.d.ts +9 -0
  163. package/dist/types/services/core/Err.d.ts +2 -0
  164. package/dist/types/services/core/Utils.d.ts +43 -13
  165. package/dist/types/services/core/WebexRequest.d.ts +1 -0
  166. package/dist/types/services/core/constants.d.ts +7 -0
  167. package/dist/types/services/core/types.d.ts +2 -0
  168. package/dist/types/services/core/websocket/WebSocketManager.d.ts +1 -0
  169. package/dist/types/services/core/websocket/types.d.ts +1 -1
  170. package/dist/types/services/index.d.ts +1 -1
  171. package/dist/types/services/task/Task.d.ts +186 -0
  172. package/dist/types/services/task/TaskFactory.d.ts +14 -0
  173. package/dist/types/services/task/TaskUtils.d.ts +54 -2
  174. package/dist/types/services/task/WebexCallingUtils.d.ts +11 -0
  175. package/dist/types/services/task/constants.d.ts +17 -0
  176. package/dist/types/services/task/contact.d.ts +4 -0
  177. package/dist/types/services/task/digital/Digital.d.ts +23 -0
  178. package/dist/types/services/task/state-machine/TaskStateMachine.d.ts +1442 -0
  179. package/dist/types/services/task/state-machine/actions.d.ts +10 -0
  180. package/dist/types/services/task/state-machine/constants.d.ts +107 -0
  181. package/dist/types/services/task/state-machine/guards.d.ts +103 -0
  182. package/dist/types/services/task/state-machine/index.d.ts +13 -0
  183. package/dist/types/services/task/state-machine/types.d.ts +277 -0
  184. package/dist/types/services/task/state-machine/uiControlsComputer.d.ts +9 -0
  185. package/dist/types/services/task/taskDataNormalizer.d.ts +10 -0
  186. package/dist/types/services/task/types.d.ts +738 -66
  187. package/dist/types/services/task/voice/Voice.d.ts +241 -0
  188. package/dist/types/services/task/voice/WebRTC.d.ts +54 -0
  189. package/dist/types/services/task/voice/wxAppOfferObservability.d.ts +39 -0
  190. package/dist/types/services/task/voice/wxAppVoiceMethods.d.ts +68 -0
  191. package/dist/types/services/wxAppDiagnosticLogging.d.ts +63 -0
  192. package/dist/types/services/wxAppTelephonyUtils.d.ts +5 -0
  193. package/dist/types/types.d.ts +213 -11
  194. package/dist/types/utils/PageCache.d.ts +20 -3
  195. package/dist/types/webex.d.ts +1 -0
  196. package/dist/types.js +168 -6
  197. package/dist/types.js.map +1 -1
  198. package/dist/utils/PageCache.js +19 -5
  199. package/dist/utils/PageCache.js.map +1 -1
  200. package/dist/webex.js +22 -2
  201. package/dist/webex.js.map +1 -1
  202. package/package.json +16 -12
  203. package/src/cc.ts +1137 -67
  204. package/src/config.ts +13 -0
  205. package/src/constants.ts +39 -1
  206. package/src/index.ts +62 -15
  207. package/src/metrics/MetricsManager.ts +16 -0
  208. package/src/metrics/ai-docs/AGENTS.md +350 -0
  209. package/src/metrics/ai-docs/ARCHITECTURE.md +338 -0
  210. package/src/metrics/ai-docs/metrics-spec.md +971 -0
  211. package/src/metrics/behavioral-events.ts +190 -0
  212. package/src/metrics/constants.ts +59 -4
  213. package/src/services/AddressBook.ts +17 -6
  214. package/src/services/AnswerCallOnWebexService.ts +239 -0
  215. package/src/services/ApiAiAssistant.ts +494 -15
  216. package/src/services/EntryPoint.ts +59 -60
  217. package/src/services/Queue.ts +29 -12
  218. package/src/services/UserPreference.ts +509 -0
  219. package/src/services/WebCallingService.ts +16 -2
  220. package/src/services/WebexCrossClientService.ts +298 -0
  221. package/src/services/WxAppTelephonyMercurySync.ts +142 -0
  222. package/src/services/agent/ai-docs/AGENTS.md +240 -0
  223. package/src/services/agent/ai-docs/ARCHITECTURE.md +304 -0
  224. package/src/services/agent/ai-docs/agent-spec.md +505 -0
  225. package/src/services/ai-docs/AGENTS.md +386 -0
  226. package/src/services/ai-docs/services-spec.md +512 -0
  227. package/src/services/config/Util.ts +54 -84
  228. package/src/services/config/ai-docs/AGENTS.md +250 -0
  229. package/src/services/config/ai-docs/ARCHITECTURE.md +413 -0
  230. package/src/services/config/ai-docs/config-spec.md +669 -0
  231. package/src/services/config/constants.ts +63 -85
  232. package/src/services/config/index.ts +116 -277
  233. package/src/services/config/types.ts +229 -125
  234. package/src/services/constants.ts +10 -0
  235. package/src/services/core/Err.ts +1 -0
  236. package/src/services/core/Utils.ts +151 -37
  237. package/src/services/core/WebexRequest.ts +3 -1
  238. package/src/services/core/ai-docs/AGENTS.md +381 -0
  239. package/src/services/core/ai-docs/ARCHITECTURE.md +698 -0
  240. package/src/services/core/ai-docs/core-spec.md +797 -0
  241. package/src/services/core/aqm-reqs.ts +18 -12
  242. package/src/services/core/constants.ts +8 -0
  243. package/src/services/core/types.ts +33 -1
  244. package/src/services/core/websocket/WebSocketManager.ts +28 -2
  245. package/src/services/core/websocket/types.ts +1 -1
  246. package/src/services/index.ts +1 -1
  247. package/src/services/task/Task.ts +1211 -0
  248. package/src/services/task/TaskFactory.ts +82 -0
  249. package/src/services/task/TaskManager.ts +1585 -724
  250. package/src/services/task/TaskUtils.ts +316 -25
  251. package/src/services/task/WebexCallingUtils.ts +136 -0
  252. package/src/services/task/ai-docs/AGENTS.md +457 -0
  253. package/src/services/task/ai-docs/ARCHITECTURE.md +595 -0
  254. package/src/services/task/ai-docs/task-spec.md +1501 -0
  255. package/src/services/task/constants.ts +18 -0
  256. package/src/services/task/contact.ts +30 -0
  257. package/src/services/task/digital/Digital.ts +102 -0
  258. package/src/services/task/state-machine/TaskStateMachine.ts +1320 -0
  259. package/src/services/task/state-machine/actions.ts +741 -0
  260. package/src/services/task/state-machine/ai-docs/AGENTS.md +460 -0
  261. package/src/services/task/state-machine/ai-docs/ARCHITECTURE.md +1156 -0
  262. package/src/services/task/state-machine/ai-docs/task-state-machine-spec.md +2247 -0
  263. package/src/services/task/state-machine/constants.ts +172 -0
  264. package/src/services/task/state-machine/guards.ts +442 -0
  265. package/src/services/task/state-machine/index.ts +28 -0
  266. package/src/services/task/state-machine/types.ts +258 -0
  267. package/src/services/task/state-machine/uiControlsComputer.ts +1135 -0
  268. package/src/services/task/taskDataNormalizer.ts +137 -0
  269. package/src/services/task/types.ts +918 -70
  270. package/src/services/task/voice/Voice.ts +1878 -0
  271. package/src/services/task/voice/WebRTC.ts +194 -0
  272. package/src/services/task/voice/wxAppOfferObservability.ts +204 -0
  273. package/src/services/task/voice/wxAppVoiceMethods.ts +575 -0
  274. package/src/services/wxAppDiagnosticLogging.ts +286 -0
  275. package/src/services/wxAppTelephonyUtils.ts +14 -0
  276. package/src/types.ts +272 -13
  277. package/src/utils/AGENTS.md +289 -0
  278. package/src/utils/PageCache.ts +38 -5
  279. package/src/utils/ai-docs/utils-spec.md +391 -0
  280. package/src/webex.js +10 -0
  281. package/test/unit/fixtures/aiSummaryTestUtils.ts +40 -0
  282. package/test/unit/spec/cc.ts +3553 -107
  283. package/test/unit/spec/index.ts +885 -0
  284. package/test/unit/spec/logger-proxy.ts +70 -0
  285. package/test/unit/spec/metrics/MetricsManager.ts +25 -0
  286. package/test/unit/spec/metrics/behavioral-events.ts +60 -0
  287. package/test/unit/spec/services/AddressBook.ts +37 -6
  288. package/test/unit/spec/services/AnswerCallOnWebexService.ts +264 -0
  289. package/test/unit/spec/services/ApiAiAssistant.ts +442 -23
  290. package/test/unit/spec/services/EntryPoint.ts +87 -40
  291. package/test/unit/spec/services/Queue.ts +123 -12
  292. package/test/unit/spec/services/UserPreference.ts +401 -0
  293. package/test/unit/spec/services/WebCallingService.ts +45 -1
  294. package/test/unit/spec/services/WebexCrossClientService.ts +509 -0
  295. package/test/unit/spec/services/WxAppTelephonyMercurySync.ts +136 -0
  296. package/test/unit/spec/services/config/Util.ts +501 -0
  297. package/test/unit/spec/services/config/index.ts +317 -547
  298. package/test/unit/spec/services/core/Utils.ts +447 -8
  299. package/test/unit/spec/services/core/WebexRequest.ts +8 -7
  300. package/test/unit/spec/services/core/aqm-reqs.ts +142 -1
  301. package/test/unit/spec/services/core/websocket/WebSocketManager.ts +129 -53
  302. package/test/unit/spec/services/task/AutoWrapup.ts +63 -0
  303. package/test/unit/spec/services/task/Task.ts +2723 -0
  304. package/test/unit/spec/services/task/TaskFactory.ts +116 -0
  305. package/test/unit/spec/services/task/TaskManager.ts +4734 -1769
  306. package/test/unit/spec/services/task/TaskUtils.ts +307 -0
  307. package/test/unit/spec/services/task/WebexCallingUtils.ts +153 -0
  308. package/test/unit/spec/services/task/contact.ts +33 -0
  309. package/test/unit/spec/services/task/digital/Digital.ts +105 -0
  310. package/test/unit/spec/services/task/state-machine/TaskStateMachine.ts +4060 -0
  311. package/test/unit/spec/services/task/state-machine/guards.ts +839 -0
  312. package/test/unit/spec/services/task/state-machine/types.ts +18 -0
  313. package/test/unit/spec/services/task/state-machine/uiControlsComputer.ts +3101 -0
  314. package/test/unit/spec/services/task/taskTestUtils.ts +87 -0
  315. package/test/unit/spec/services/task/voice/Voice.ts +2355 -0
  316. package/test/unit/spec/services/task/voice/WebRTC.ts +235 -0
  317. package/test/unit/spec/services/task/voice/wxAppOfferObservability.ts +361 -0
  318. package/test/unit/spec/services/task/voice/wxAppVoiceMethods.ts +719 -0
  319. package/test/unit/spec/services/wxAppDiagnosticLogging.ts +179 -0
  320. package/test/unit/spec/wellnessSampleUtils.ts +288 -0
  321. package/typedoc.md +1 -1
  322. package/umd/contact-center.min.js +2 -2
  323. package/umd/contact-center.min.js.map +1 -1
  324. package/dist/services/task/index.js +0 -1530
  325. package/dist/services/task/index.js.map +0 -1
  326. package/dist/types/services/task/index.d.ts +0 -650
  327. package/src/services/task/index.ts +0 -1806
  328. package/test/unit/spec/services/task/index.ts +0 -2205
@@ -1,7 +1,11 @@
1
1
  /* eslint-disable @typescript-eslint/no-explicit-any */
2
2
  import {WebSocketManager} from '../../../../../../src/services/core/websocket/WebSocketManager';
3
3
  import {WebexSDK, SubscribeRequest} from '../../../../../../src/types';
4
- import {SUBSCRIBE_API, WCC_API_GATEWAY} from '../../../../../../src/services/constants';
4
+ import {
5
+ RTD_SUBSCRIBE_API,
6
+ SUBSCRIBE_API,
7
+ WCC_API_GATEWAY,
8
+ } from '../../../../../../src/services/constants';
5
9
  import {WEB_SOCKET_MANAGER_FILE} from '../../../../../../src/constants';
6
10
  import LoggerProxy from '../../../../../../src/logger-proxy';
7
11
 
@@ -18,10 +22,10 @@ jest.mock('../../../../../../src/logger-proxy', () => ({
18
22
 
19
23
  class MockWebSocket {
20
24
  static inst: MockWebSocket;
21
- onopen: () => void = () => { };
22
- onerror: (event: any) => void = () => { };
23
- onclose: (event: any) => void = () => { };
24
- onmessage: (msg: any) => void = () => { };
25
+ onopen: () => void = () => {};
26
+ onerror: (event: any) => void = () => {};
27
+ onclose: (event: any) => void = () => {};
28
+ onmessage: (msg: any) => void = () => {};
25
29
  close = jest.fn();
26
30
  send = jest.fn();
27
31
 
@@ -37,7 +41,7 @@ class MockWebSocket {
37
41
  class MockCustomEvent<T> extends Event {
38
42
  detail: T;
39
43
 
40
- constructor(event: string, params: { detail: T }) {
44
+ constructor(event: string, params: {detail: T}) {
41
45
  super(event);
42
46
  this.detail = params.detail;
43
47
  }
@@ -49,7 +53,7 @@ global.CustomEvent = MockCustomEvent as any;
49
53
  class MockMessageEvent extends Event {
50
54
  data: any;
51
55
 
52
- constructor(type: string, eventInitDict: { data: any }) {
56
+ constructor(type: string, eventInitDict: {data: any}) {
53
57
  super(type);
54
58
  this.data = eventInitDict.data;
55
59
  }
@@ -90,21 +94,23 @@ describe('WebSocketManager', () => {
90
94
  };
91
95
 
92
96
  global.Worker = jest.fn(() => mockWorker) as any;
93
- global.WebSocket = MockWebSocket as any;
97
+ global.WebSocket = jest.fn(function (this: any, ...args: any[]) {
98
+ return new MockWebSocket(...(args as []));
99
+ }) as any;
94
100
 
95
101
  global.Blob = function (content: any[], options: any) {
96
- return { content, options };
102
+ return {content, options};
97
103
  } as any;
98
104
 
99
105
  global.URL.createObjectURL = function (blob: Blob) {
100
106
  return 'blob:http://localhost:3000/12345';
101
107
  };
102
108
 
103
- webSocketManager = new WebSocketManager({ webex: mockWebex });
109
+ webSocketManager = new WebSocketManager({webex: mockWebex});
104
110
 
105
111
  setTimeout(() => {
106
112
  MockWebSocket.inst.onopen();
107
- MockWebSocket.inst.onmessage({ data: JSON.stringify({ type: "Welcome" }) });
113
+ MockWebSocket.inst.onmessage({data: JSON.stringify({type: 'Welcome'})});
108
114
  }, 1);
109
115
 
110
116
  console.log = jest.fn();
@@ -115,10 +121,58 @@ describe('WebSocketManager', () => {
115
121
  expect(webSocketManager).toBeDefined();
116
122
  });
117
123
 
124
+ describe('webSocketUrl validation', () => {
125
+ it('rejects a non-wss webSocketUrl and does not construct a socket', async () => {
126
+ const subscribeResponse = {
127
+ body: {
128
+ webSocketUrl: 'http://fake-url.cisco.com',
129
+ },
130
+ };
131
+
132
+ (mockWebex.request as jest.Mock).mockResolvedValueOnce(subscribeResponse);
133
+
134
+ await expect(
135
+ webSocketManager.initWebSocket({body: fakeSubscribeRequest, resource: SUBSCRIBE_API})
136
+ ).rejects.toBeDefined();
137
+
138
+ expect(global.WebSocket).not.toHaveBeenCalled();
139
+ });
140
+
141
+ it('rejects a wss webSocketUrl with a non-allow-listed host and does not construct a socket', async () => {
142
+ const subscribeResponse = {
143
+ body: {
144
+ webSocketUrl: 'wss://evil.attacker.com',
145
+ },
146
+ };
147
+
148
+ (mockWebex.request as jest.Mock).mockResolvedValueOnce(subscribeResponse);
149
+
150
+ await expect(
151
+ webSocketManager.initWebSocket({body: fakeSubscribeRequest, resource: SUBSCRIBE_API})
152
+ ).rejects.toBeDefined();
153
+
154
+ expect(global.WebSocket).not.toHaveBeenCalled();
155
+ });
156
+
157
+ it('connects for a valid wss allow-listed webSocketUrl', async () => {
158
+ const subscribeResponse = {
159
+ body: {
160
+ webSocketUrl: 'wss://notifs.wxcc-us1.cisco.com',
161
+ },
162
+ };
163
+
164
+ (mockWebex.request as jest.Mock).mockResolvedValueOnce(subscribeResponse);
165
+
166
+ await webSocketManager.initWebSocket({body: fakeSubscribeRequest, resource: SUBSCRIBE_API});
167
+
168
+ expect(global.WebSocket).toHaveBeenCalledWith('wss://notifs.wxcc-us1.cisco.com');
169
+ });
170
+ });
171
+
118
172
  it('should register and connect to WebSocket with X-ORGANIZATION-ID header for INT environment', async () => {
119
173
  const subscribeResponse = {
120
174
  body: {
121
- webSocketUrl: 'wss://fake-url',
175
+ webSocketUrl: 'wss://fake-url.cisco.com',
122
176
  },
123
177
  };
124
178
 
@@ -126,7 +180,7 @@ describe('WebSocketManager', () => {
126
180
  (mockWebex.internal.services.isIntegrationEnvironment as jest.Mock).mockReturnValue(true);
127
181
  (mockWebex.request as jest.Mock).mockResolvedValueOnce(subscribeResponse);
128
182
 
129
- await webSocketManager.initWebSocket({ body: fakeSubscribeRequest, resource: SUBSCRIBE_API });
183
+ await webSocketManager.initWebSocket({body: fakeSubscribeRequest, resource: SUBSCRIBE_API});
130
184
 
131
185
  expect(mockWebex.request).toHaveBeenCalledWith({
132
186
  service: WCC_API_GATEWAY,
@@ -137,13 +191,35 @@ describe('WebSocketManager', () => {
137
191
  });
138
192
  });
139
193
 
140
- it('should register and connect to WebSocket without X-ORGANIZATION-ID header for production environment', async () => {
194
+ it('should connect rtd websocket', async () => {
141
195
  const subscribeResponse = {
142
196
  body: {
143
- webSocketUrl: 'wss://fake-url',
197
+ webSocketUrl: 'wss://fake-url.cisco.com',
144
198
  },
145
199
  };
146
200
 
201
+ (mockWebex.request as jest.Mock).mockResolvedValueOnce(subscribeResponse);
202
+
203
+ await webSocketManager.initWebSocket({
204
+ body: fakeSubscribeRequest,
205
+ resource: RTD_SUBSCRIBE_API,
206
+ });
207
+
208
+ expect(mockWebex.request).toHaveBeenCalledWith({
209
+ service: WCC_API_GATEWAY,
210
+ resource: RTD_SUBSCRIBE_API,
211
+ method: 'POST',
212
+ body: fakeSubscribeRequest,
213
+ headers: {'X-ORGANIZATION-ID': 'test-org-id'},
214
+ });
215
+ });
216
+
217
+ it('should register and connect to WebSocket without X-ORGANIZATION-ID header for production environment', async () => {
218
+ const subscribeResponse = {
219
+ body: {
220
+ webSocketUrl: 'wss://fake-url.cisco.com',
221
+ },
222
+ };
147
223
  // Mock production environment (services.isIntegrationEnvironment returns false)
148
224
  (mockWebex.internal.services.isIntegrationEnvironment as jest.Mock).mockReturnValue(false);
149
225
  (mockWebex.request as jest.Mock).mockResolvedValueOnce(subscribeResponse);
@@ -170,7 +246,7 @@ describe('WebSocketManager', () => {
170
246
  it('should not send X-ORGANIZATION-ID header when services.isIntegrationEnvironment is not available', async () => {
171
247
  const subscribeResponse = {
172
248
  body: {
173
- webSocketUrl: 'wss://fake-url',
249
+ webSocketUrl: 'wss://fake-url.cisco.com',
174
250
  },
175
251
  };
176
252
 
@@ -219,54 +295,54 @@ describe('WebSocketManager', () => {
219
295
  it('should close WebSocket connection', async () => {
220
296
  const subscribeResponse = {
221
297
  body: {
222
- webSocketUrl: 'wss://fake-url',
298
+ webSocketUrl: 'wss://fake-url.cisco.com',
223
299
  },
224
300
  };
225
301
 
226
302
  (mockWebex.request as jest.Mock).mockResolvedValueOnce(subscribeResponse);
227
303
 
228
- await webSocketManager.initWebSocket({ body: fakeSubscribeRequest, resource: SUBSCRIBE_API });
304
+ await webSocketManager.initWebSocket({body: fakeSubscribeRequest, resource: SUBSCRIBE_API});
229
305
 
230
306
  webSocketManager.close(true, 'Test reason');
231
307
 
232
308
  expect(MockWebSocket.inst.close).toHaveBeenCalled();
233
- expect(mockWorker.postMessage).toHaveBeenCalledWith({ type: 'terminate' });
309
+ expect(mockWorker.postMessage).toHaveBeenCalledWith({type: 'terminate'});
234
310
  });
235
311
 
236
312
  it('should handle WebSocket keepalive messages', async () => {
237
313
  const subscribeResponse = {
238
314
  body: {
239
- webSocketUrl: 'wss://fake-url',
315
+ webSocketUrl: 'wss://fake-url.cisco.com',
240
316
  },
241
317
  };
242
318
 
243
319
  (mockWebex.request as jest.Mock).mockResolvedValueOnce(subscribeResponse);
244
320
 
245
- await webSocketManager.initWebSocket({ body: fakeSubscribeRequest, resource: SUBSCRIBE_API });
321
+ await webSocketManager.initWebSocket({body: fakeSubscribeRequest, resource: SUBSCRIBE_API});
246
322
 
247
323
  setTimeout(() => {
248
324
  MockWebSocket.inst.onopen();
249
- MockWebSocket.inst.onmessage({ data: JSON.stringify({ type: 'keepalive' }) });
325
+ MockWebSocket.inst.onmessage({data: JSON.stringify({type: 'keepalive'})});
250
326
  mockWorker.onmessage({
251
327
  data: {
252
- type: 'keepalive'
253
- }
328
+ type: 'keepalive',
329
+ },
254
330
  });
255
331
  }, 1);
256
332
 
257
- expect(MockWebSocket.inst.send).toHaveBeenCalledWith(JSON.stringify({ keepalive: 'true' }));
333
+ expect(MockWebSocket.inst.send).toHaveBeenCalledWith(JSON.stringify({keepalive: 'true'}));
258
334
  });
259
335
 
260
336
  it('should handle WebSocket close due to network issue', async () => {
261
337
  const subscribeResponse = {
262
338
  body: {
263
- webSocketUrl: 'wss://fake-url',
339
+ webSocketUrl: 'wss://fake-url.cisco.com',
264
340
  },
265
341
  };
266
342
 
267
343
  (mockWebex.request as jest.Mock).mockResolvedValueOnce(subscribeResponse);
268
344
 
269
- await webSocketManager.initWebSocket({ body: fakeSubscribeRequest, resource: SUBSCRIBE_API });
345
+ await webSocketManager.initWebSocket({body: fakeSubscribeRequest, resource: SUBSCRIBE_API});
270
346
 
271
347
  // Mock navigator.onLine to simulate network issue
272
348
  Object.defineProperty(global, 'navigator', {
@@ -289,10 +365,10 @@ describe('WebSocketManager', () => {
289
365
  // Wait for the close event to be handled
290
366
  await new Promise((resolve) => setTimeout(resolve, 10));
291
367
 
292
- expect(mockWorker.postMessage).toHaveBeenCalledWith({ type: 'terminate' });
368
+ expect(mockWorker.postMessage).toHaveBeenCalledWith({type: 'terminate'});
293
369
  expect(LoggerProxy.error).toHaveBeenCalledWith(
294
370
  '[WebSocketStatus] | event=webSocketClose | WebSocket connection closed REASON: network issue',
295
- { module: WEB_SOCKET_MANAGER_FILE, method: 'webSocketOnCloseHandler' }
371
+ {module: WEB_SOCKET_MANAGER_FILE, method: 'webSocketOnCloseHandler'}
296
372
  );
297
373
 
298
374
  // Restore navigator.onLine to true
@@ -307,59 +383,59 @@ describe('WebSocketManager', () => {
307
383
  it('should handle WebSocket error event', async () => {
308
384
  const subscribeResponse = {
309
385
  body: {
310
- webSocketUrl: 'wss://fake-url',
386
+ webSocketUrl: 'wss://fake-url.cisco.com',
311
387
  },
312
388
  };
313
389
 
314
390
  (mockWebex.request as jest.Mock).mockResolvedValueOnce(subscribeResponse);
315
391
 
316
- await webSocketManager.initWebSocket({ body: fakeSubscribeRequest, resource: SUBSCRIBE_API });
392
+ await webSocketManager.initWebSocket({body: fakeSubscribeRequest, resource: SUBSCRIBE_API});
317
393
 
318
394
  const errorEvent = new Event('error');
319
395
  MockWebSocket.inst.onerror(errorEvent);
320
396
 
321
397
  expect(LoggerProxy.error).toHaveBeenCalledWith(
322
398
  '[WebSocketStatus] | event=socketConnectionFailed | WebSocket connection failed [object Event]',
323
- { module: WEB_SOCKET_MANAGER_FILE, method: 'connect' }
399
+ {module: WEB_SOCKET_MANAGER_FILE, method: 'connect'}
324
400
  );
325
401
  });
326
402
 
327
403
  it('should handle WebSocket message event with AGENT_MULTI_LOGIN', async () => {
328
404
  const subscribeResponse = {
329
405
  body: {
330
- webSocketUrl: 'wss://fake-url',
406
+ webSocketUrl: 'wss://fake-url.cisco.com',
331
407
  },
332
408
  };
333
409
 
334
410
  (mockWebex.request as jest.Mock).mockResolvedValueOnce(subscribeResponse);
335
411
 
336
- await webSocketManager.initWebSocket({ body: fakeSubscribeRequest, resource: SUBSCRIBE_API });
412
+ await webSocketManager.initWebSocket({body: fakeSubscribeRequest, resource: SUBSCRIBE_API});
337
413
 
338
414
  const messageEvent = new MessageEvent('message', {
339
- data: JSON.stringify({ type: 'AGENT_MULTI_LOGIN' }),
415
+ data: JSON.stringify({type: 'AGENT_MULTI_LOGIN'}),
340
416
  });
341
417
  MockWebSocket.inst.onmessage(messageEvent);
342
418
 
343
419
  expect(MockWebSocket.inst.close).toHaveBeenCalled();
344
420
  expect(LoggerProxy.error).toHaveBeenCalledWith(
345
421
  '[WebSocketStatus] | event=agentMultiLogin | WebSocket connection closed by agent multiLogin',
346
- { module: WEB_SOCKET_MANAGER_FILE, method: 'connect' }
422
+ {module: WEB_SOCKET_MANAGER_FILE, method: 'connect'}
347
423
  );
348
424
  });
349
425
 
350
426
  it('should handle WebSocket message event with Welcome', async () => {
351
427
  const subscribeResponse = {
352
428
  body: {
353
- webSocketUrl: 'wss://fake-url',
429
+ webSocketUrl: 'wss://fake-url.cisco.com',
354
430
  },
355
431
  };
356
432
 
357
433
  (mockWebex.request as jest.Mock).mockResolvedValueOnce(subscribeResponse);
358
434
 
359
- await webSocketManager.initWebSocket({ body: fakeSubscribeRequest, resource: SUBSCRIBE_API });
435
+ await webSocketManager.initWebSocket({body: fakeSubscribeRequest, resource: SUBSCRIBE_API});
360
436
 
361
437
  const messageEvent = new MessageEvent('message', {
362
- data: JSON.stringify({ type: 'Welcome', data: { someData: 'data' } }),
438
+ data: JSON.stringify({type: 'Welcome', data: {someData: 'data'}}),
363
439
  });
364
440
  MockWebSocket.inst.onmessage(messageEvent);
365
441
 
@@ -369,13 +445,13 @@ describe('WebSocketManager', () => {
369
445
  it('should handle WebSocket close with forceCloseWebSocketOnTimeout', async () => {
370
446
  const subscribeResponse = {
371
447
  body: {
372
- webSocketUrl: 'wss://fake-url',
448
+ webSocketUrl: 'wss://fake-url.cisco.com',
373
449
  },
374
450
  };
375
451
 
376
452
  (mockWebex.request as jest.Mock).mockResolvedValueOnce(subscribeResponse);
377
453
 
378
- await webSocketManager.initWebSocket({ body: fakeSubscribeRequest, resource: SUBSCRIBE_API });
454
+ await webSocketManager.initWebSocket({body: fakeSubscribeRequest, resource: SUBSCRIBE_API});
379
455
 
380
456
  webSocketManager['forceCloseWebSocketOnTimeout'] = true;
381
457
 
@@ -394,23 +470,23 @@ describe('WebSocketManager', () => {
394
470
  // Wait for the close event to be handled
395
471
  await new Promise((resolve) => setTimeout(resolve, 10));
396
472
 
397
- expect(mockWorker.postMessage).toHaveBeenCalledWith({ type: 'terminate' });
473
+ expect(mockWorker.postMessage).toHaveBeenCalledWith({type: 'terminate'});
398
474
  expect(LoggerProxy.error).toHaveBeenCalledWith(
399
475
  '[WebSocketStatus] | event=webSocketClose | WebSocket connection closed REASON: WebSocket auto close timed out. Forcefully closed websocket.',
400
- { module: WEB_SOCKET_MANAGER_FILE, method: 'webSocketOnCloseHandler' }
476
+ {module: WEB_SOCKET_MANAGER_FILE, method: 'webSocketOnCloseHandler'}
401
477
  );
402
478
  });
403
479
 
404
480
  it('should handle WebSocket close without reconnect', async () => {
405
481
  const subscribeResponse = {
406
482
  body: {
407
- webSocketUrl: 'wss://fake-url',
483
+ webSocketUrl: 'wss://fake-url.cisco.com',
408
484
  },
409
485
  };
410
486
 
411
487
  (mockWebex.request as jest.Mock).mockResolvedValueOnce(subscribeResponse);
412
488
 
413
- await webSocketManager.initWebSocket({ body: fakeSubscribeRequest, resource: SUBSCRIBE_API });
489
+ await webSocketManager.initWebSocket({body: fakeSubscribeRequest, resource: SUBSCRIBE_API});
414
490
  webSocketManager.shouldReconnect = false;
415
491
  // Simulate the WebSocket close event
416
492
  setTimeout(() => {
@@ -421,26 +497,26 @@ describe('WebSocketManager', () => {
421
497
  target: MockWebSocket.inst,
422
498
  });
423
499
  }, 1);
424
-
500
+
425
501
  await new Promise((resolve) => setTimeout(resolve, 10));
426
502
 
427
- expect(mockWorker.postMessage).toHaveBeenCalledWith({ type: 'terminate' });
503
+ expect(mockWorker.postMessage).toHaveBeenCalledWith({type: 'terminate'});
428
504
  expect(LoggerProxy.error).not.toHaveBeenCalledWith(
429
505
  '[WebSocketStatus] | event=webSocketClose | WebSocket connection closed REASON: no reconnect',
430
- { module: WEB_SOCKET_MANAGER_FILE, method: 'webSocketOnCloseHandler' }
506
+ {module: WEB_SOCKET_MANAGER_FILE, method: 'webSocketOnCloseHandler'}
431
507
  );
432
508
  });
433
509
 
434
510
  it('should handle WebSocket close with clean close', async () => {
435
511
  const subscribeResponse = {
436
512
  body: {
437
- webSocketUrl: 'wss://fake-url',
513
+ webSocketUrl: 'wss://fake-url.cisco.com',
438
514
  },
439
515
  };
440
516
 
441
517
  (mockWebex.request as jest.Mock).mockResolvedValueOnce(subscribeResponse);
442
518
 
443
- await webSocketManager.initWebSocket({ body: fakeSubscribeRequest, resource: SUBSCRIBE_API });
519
+ await webSocketManager.initWebSocket({body: fakeSubscribeRequest, resource: SUBSCRIBE_API});
444
520
 
445
521
  // Simulate the WebSocket close event
446
522
  setTimeout(() => {
@@ -455,10 +531,10 @@ describe('WebSocketManager', () => {
455
531
  // Wait for the close event to be handled
456
532
  await new Promise((resolve) => setTimeout(resolve, 10));
457
533
 
458
- expect(mockWorker.postMessage).toHaveBeenCalledWith({ type: 'terminate' });
534
+ expect(mockWorker.postMessage).toHaveBeenCalledWith({type: 'terminate'});
459
535
  expect(LoggerProxy.error).not.toHaveBeenCalledWith(
460
536
  '[WebSocketStatus] | event=webSocketClose | WebSocket connection closed REASON: clean close',
461
- { module: WEB_SOCKET_MANAGER_FILE, method: 'webSocketOnCloseHandler' }
537
+ {module: WEB_SOCKET_MANAGER_FILE, method: 'webSocketOnCloseHandler'}
462
538
  );
463
539
  });
464
- });
540
+ });
@@ -0,0 +1,63 @@
1
+ import AutoWrapup from '../../../../../src/services/task/AutoWrapup';
2
+
3
+ describe('AutoWrapup', () => {
4
+ beforeEach(() => {
5
+ jest.useFakeTimers();
6
+ });
7
+
8
+ afterEach(() => {
9
+ jest.useRealTimers();
10
+ });
11
+
12
+ it('starts, reports running, and completes', () => {
13
+ const onComplete = jest.fn();
14
+ const timer = new AutoWrapup(1000, true);
15
+
16
+ expect(timer.allowCancelAutoWrapup).toBe(true);
17
+ expect(timer.isRunning()).toBe(false);
18
+
19
+ timer.start(onComplete);
20
+ expect(timer.isRunning()).toBe(true);
21
+ expect(timer.getTimeLeft()).toBeGreaterThan(0);
22
+ expect(timer.getTimeLeftSeconds()).toBeGreaterThan(0);
23
+
24
+ jest.advanceTimersByTime(1000);
25
+ expect(onComplete).toHaveBeenCalledTimes(1);
26
+ expect(timer.isRunning()).toBe(false);
27
+ });
28
+
29
+ it('clear() is safe when not running and cancels an active timer', () => {
30
+ const onComplete = jest.fn();
31
+ const timer = new AutoWrapup(1000);
32
+
33
+ timer.clear(); // no-op
34
+ expect(timer.isRunning()).toBe(false);
35
+
36
+ timer.start(onComplete);
37
+ expect(timer.isRunning()).toBe(true);
38
+
39
+ timer.clear();
40
+ expect(timer.isRunning()).toBe(false);
41
+
42
+ jest.advanceTimersByTime(1000);
43
+ expect(onComplete).not.toHaveBeenCalled();
44
+ });
45
+
46
+ it('start() replaces an existing timer', () => {
47
+ const onComplete1 = jest.fn();
48
+ const onComplete2 = jest.fn();
49
+ const timer = new AutoWrapup(1000);
50
+
51
+ timer.start(onComplete1);
52
+ jest.advanceTimersByTime(500);
53
+
54
+ timer.start(onComplete2);
55
+ jest.advanceTimersByTime(500);
56
+ expect(onComplete1).not.toHaveBeenCalled();
57
+ expect(onComplete2).not.toHaveBeenCalled();
58
+
59
+ jest.advanceTimersByTime(500);
60
+ expect(onComplete2).toHaveBeenCalledTimes(1);
61
+ });
62
+ });
63
+