@webex/contact-center 3.12.0-next.17 → 3.12.0-next.170

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
@@ -0,0 +1,797 @@
1
+ # Core — SPEC
2
+
3
+ > Start here → root [`AGENTS.md`](../../../../AGENTS.md) · router [`SPEC_INDEX.md`](../../../../ai-docs/SPEC_INDEX.md) · system [`ARCHITECTURE.md`](../../../../ai-docs/ARCHITECTURE.md). This is the module's canonical specification.
4
+
5
+ ## Metadata
6
+
7
+ | Field | Value |
8
+ |---|---|
9
+ | Module id | `core` |
10
+ | Source path(s) | `src/services/core` |
11
+ | Doc kind | Module spec |
12
+ | Coverage score | Partial (manifest-authoritative); 15/15 required document fields present |
13
+ | Generated from | `module-spec` @ SDLC template library `0.2.1` |
14
+ | generated_by / approved_by / updated_at | Codex generator / developer-approved follow-up review remediation / 2026-07-21 |
15
+ | Validation status | Follow-up validation passed (independent Claude fallback, 2026-07-21); coverage remains Partial |
16
+
17
+ ## Evidence Rules
18
+ Every requirement cites stable source and test file paths. Code/tests are the behavioral referee; routed source text supplies explicit intent and rationale. Missing or contradictory evidence blocks promotion.
19
+
20
+ ## Source Material Register
21
+ | Source material | Scope | Decision | Detail location or disposition |
22
+ |---|---|---|---|
23
+ | Reviewed prior module guides and architecture material | overview / architecture / API / tests | used and code-checked | Content is placed by meaning throughout this specification; exact routing remains in the manifest. |
24
+
25
+ ## Overview
26
+ Core is one of nine confirmed Contact Center SDK modules. Own authenticated HTTP, realtime WebSocket lifecycle, AQM request correlation, reconnect/keepalive behavior, and shared error normalization. Existing reviewed documentation is migrated by meaning and code/tests remain the behavioral referee.
27
+
28
+ The Core service provides the foundational infrastructure layer that all other services depend on:
29
+
30
+ - **WebSocket Communication**: Real-time bidirectional messaging with the contact center backend, including automatic reconnection and keepalive management
31
+
32
+ - **HTTP Request Handling**: Authenticated REST API calls to WCC API Gateway with built-in error handling and log upload support
33
+
34
+ - **AQM Request/Response Pattern**: A structured pattern used by the routing and contact layers to send HTTP requests to the contact center backend and correlate responses/failures via WebSocket notifications
35
+
36
+ - **Error Handling & Logging**: Standardized error extraction, logging via `LoggerProxy`, and log upload utilities that all services use for consistent error reporting
37
+
38
+ | Component | File | Description |
39
+ |---|---|---|
40
+ | `WebSocketManager` | [`WebSocketManager.ts`](../websocket/WebSocketManager.ts) | Manages the WebSocket connection lifecycle including initialization, message dispatch, and graceful shutdown. Validates the subscribe/register `webSocketUrl` against the RoutingNotifs allow-list before opening a socket. Emits `message` events for incoming data and `socketClose` when the connection drops while reconnect is allowed. |
41
+ | `ConnectionService` | [`connection-service.ts`](../websocket/connection-service.ts) | Orchestrates reconnection logic and keepalive heartbeats on top of `WebSocketManager`. Detects connection loss/recovery and emits `connectionLost` details; ContactCenter owns any `silentRelogin()` policy. |
42
+ | `WebexRequest` | [`WebexRequest.ts`](../WebexRequest.ts) | Singleton HTTP client that forwards service/resource/method/body options to the authenticated host request API and provides `uploadLogs` diagnostics. |
43
+ | `AqmReqs` | [`aqm-reqs.ts`](../aqm-reqs.ts) | Factory for creating request methods that send HTTP requests and wait for correlated WebSocket notifications (success or failure). Used by routing and task services to implement their API methods. |
44
+ | `Utils` | [`Utils.ts`](../Utils.ts) | Shared utility functions including `getErrorDetails()` for standardized error handling, `generateTaskErrorObject()` for task-specific errors, and `createErrDetailsObject()` for constructing error detail objects. |
45
+ | `Err` | [`Err.ts`](../Err.ts) | Error class definitions. `Err.Details` carries structured error metadata (status, type, trackingId) for consistent error propagation. |
46
+ | `constants` | [`constants.ts`](../constants.ts) | Timeout values, interval durations, participant types, interaction states, method name constants, and the `ALLOWED_ROUTING_NOTIFS_DOMAINS` WebSocket host allow-list used throughout the core layer. Any new constants for core should be defined here. |
47
+
48
+ ## Purpose / Responsibility
49
+ Own authenticated HTTP, realtime WebSocket lifecycle, AQM request correlation, reconnect/keepalive behavior, and shared error normalization.
50
+
51
+ ## Stack
52
+ TypeScript/JavaScript, WebSocket, Web Worker keepalive, EventEmitter, Webex request client, Jest 27.
53
+
54
+ ## Folder / Package Structure
55
+ ```text
56
+ src/services/core/
57
+ ├── Err.ts
58
+ ├── GlobalTypes.ts
59
+ ├── Utils.ts
60
+ ├── WebexRequest.ts
61
+ ├── aqm-reqs.ts
62
+ ├── constants.ts
63
+ ├── types.ts
64
+ ├── websocket/
65
+ ```
66
+
67
+ ```text
68
+ services/core/
69
+ ├── aqm-reqs.ts # AQM request handler
70
+ ├── constants.ts # Core constants
71
+ ├── Err.ts # Error classes
72
+ ├── GlobalTypes.ts # Failure, Msg<T>, etc.
73
+ ├── types.ts # Request/response types
74
+ ├── Utils.ts # Utility functions
75
+ ├── WebexRequest.ts # HTTP client
76
+ └── websocket/
77
+ ├── WebSocketManager.ts # Main WS handler
78
+ ├── connection-service.ts # Connection lifecycle
79
+ ├── keepalive.worker.js # Keepalive worker
80
+ └── types.ts # WS types
81
+ ```
82
+
83
+ ## Key Files (source of truth)
84
+ | File | Holds |
85
+ |---|---|
86
+ | `src/services/core/WebexRequest.ts` | Authoritative Core implementation or contract source. |
87
+ | `src/services/core/aqm-reqs.ts` | Authoritative Core implementation or contract source. |
88
+ | `src/services/core/Utils.ts` | Authoritative Core implementation or contract source. |
89
+ | `src/services/core/Err.ts` | Authoritative Core implementation or contract source. |
90
+ | `src/services/core/websocket/WebSocketManager.ts` | Authoritative Core implementation or contract source. |
91
+ | `src/services/core/websocket/connection-service.ts` | Authoritative Core implementation or contract source. |
92
+
93
+ ## Public Surface
94
+ | Contract ID | Type | Surface | Purpose | Compatibility / deprecation | Schema / detail link | Root index |
95
+ |---|---|---|---|---|---|---|
96
+ | `core.surface` | SDK / event / internal API | Internal WebexRequest, WebSocketManager, ConnectionService, AqmReqs, and shared error/request types and helpers. | Stable module consumption boundary. | Additive changes by default; breaking package exports require a major-version transition. | `src/services/core/WebexRequest.ts` | `../../../../ai-docs/CONTRACTS.md` |
97
+
98
+ Compatibility notes:
99
+ - Do not remove or reinterpret exported symbols/events without a documented consumer migration.
100
+
101
+ | Event | Data | Description |
102
+ |---|---|---|
103
+ | `message` | string (JSON) | WebSocket message received |
104
+ | `socketClose` | - | Socket closed while reconnect is allowed |
105
+
106
+ Generic message wrapper used throughout the SDK. All WebSocket messages and AQM responses conform to this shape:
107
+
108
+ ```typescript
109
+ export type Msg<T = any> = {
110
+ type: string; // Message/Event type identifier
111
+ orgId: string; // Organization identifier
112
+ trackingId: string; // Unique tracking identifier
113
+ data: T; // Message/Event payload data
114
+ };
115
+
116
+ // Usage — the payload type goes into `data`
117
+ export type LoginSuccess = Msg<{
118
+ agentId: string;
119
+ status: string;
120
+ // ...
121
+ }>;
122
+ // Resulting shape: { type, orgId, trackingId, data: { agentId, status, ... } }
123
+ ```
124
+
125
+ ### ConnectionService internal surface — not public contracts
126
+
127
+ The only public method in the following list is `setConnectionProp`. The remaining methods are private implementation details documented for ownership and maintenance; they are not public API contracts.
128
+
129
+ 1. `setConnectionProp(prop: ConnectionProp): void` (public)
130
+
131
+ - **Purpose**: Updates connection-level runtime settings used by timers (mainly recovery timeout behavior).
132
+
133
+ - **Params**: `prop` - new connection config object.
134
+
135
+ - **Returns**: `void`.
136
+
137
+ - **Usage**: Called by higher layers when timeout behavior must be tuned after initialization.
138
+
139
+ 2. `setupEventListeners(): void` (private)
140
+
141
+ - **Purpose**: Wires `WebSocketManager` events to internal handlers (`'message' -> onPing`, `'socketClose' -> onSocketClose`).
142
+
143
+ - **Params**: none.
144
+
145
+ - **Returns**: `void`.
146
+
147
+ - **Usage**: Invoked from the constructor once, during `ConnectionService` setup.
148
+
149
+ 3. `onPing(event: any): void` (private)
150
+
151
+ - **Purpose**: Handles every incoming socket message, resets timers, updates keepalive/recovery flags, and emits recovery events when state changes.
152
+
153
+ - **Params**: `event` - raw message payload (JSON string) received from the socket event stream.
154
+
155
+ - **Returns**: `void`.
156
+
157
+ - **Usage**: Triggered automatically by the `'message'` listener.
158
+
159
+ 4. `onSocketClose(): void` (private)
160
+
161
+ - **Purpose**: Starts the reconnect interval when socket close is detected.
162
+
163
+ - **Params**: none.
164
+
165
+ - **Returns**: `void`.
166
+
167
+ - **Usage**: Triggered automatically by the `'socketClose'` listener.
168
+
169
+ 5. `handleSocketClose(): Promise<void>` (private)
170
+
171
+ - **Purpose**: Performs one reconnect attempt; if browser is online, reinitializes WebSocket and marks socket as reconnected.
172
+
173
+ - **Params**: none.
174
+
175
+ - **Returns**: `Promise<void>` (rejects when browser is offline).
176
+
177
+ - **Usage**: Called repeatedly from `onSocketClose` interval loop.
178
+
179
+ 6. `handleConnectionLost(): void` (private)
180
+
181
+ - **Purpose**: Marks the connection as lost and dispatches a connection status event.
182
+
183
+ - **Params**: none.
184
+
185
+ - **Returns**: `void`.
186
+
187
+ - **Usage**: Scheduled by `onPing` via `reconnectingTimer` after inactivity.
188
+
189
+ 7. `handleRestoreFailed(): Promise<void>` (private)
190
+
191
+ - **Purpose**: Marks restore as failed, disables reconnect, emits failure state, and clears reconnect interval.
192
+
193
+ - **Params**: none.
194
+
195
+ - **Returns**: `Promise<void>`.
196
+
197
+ - **Usage**: Scheduled by `onPing` via `restoreTimer`.
198
+
199
+ 8. `clearTimerOnRestoreFailed(): Promise<void>` (private)
200
+
201
+ - **Purpose**: Stops active reconnect interval to avoid duplicate retries.
202
+
203
+ - **Params**: none.
204
+
205
+ - **Returns**: `Promise<void>`.
206
+
207
+ - **Usage**: Called from reconnect/failure paths whenever interval cleanup is needed.
208
+
209
+ 9. `updateConnectionData(): void` (private)
210
+
211
+ - **Purpose**: Resets transient connection flags (`isConnectionLost`, `isRestoreFailed`, `isSocketReconnected`) after recovery.
212
+
213
+ - **Params**: none.
214
+
215
+ - **Returns**: `void`.
216
+
217
+ - **Usage**: Called inside `onPing` before dispatching recovered state.
218
+
219
+ 10. `dispatchConnectionEvent(socketReconnected = false): void` (private)
220
+
221
+ - **Purpose**: Builds `ConnectionLostDetails`, forwards it to `WebSocketManager.handleConnectionLost`, and emits `'connectionLost'`.
222
+
223
+ - **Params**: `socketReconnected` - optional override used when reconnect is explicitly detected.
224
+
225
+ - **Returns**: `void`.
226
+
227
+ - **Usage**: Used by lost/recovered/restore-failed paths to publish uniform connection state.
228
+
229
+ ```typescript
230
+ type ConnectionLostDetails = {
231
+ isConnectionLost: boolean;
232
+ isRestoreFailed: boolean;
233
+ isSocketReconnected: boolean;
234
+ isKeepAlive: boolean;
235
+ };
236
+
237
+ connectionService.on('connectionLost', (details: ConnectionLostDetails) => {
238
+ if (details.isConnectionLost) {
239
+ // Connection lost — waiting for recovery
240
+ } else if (details.isRestoreFailed) {
241
+ // Recovery timeout (50 s) exceeded
242
+ } else if (details.isSocketReconnected) {
243
+ // Socket successfully reconnected
244
+ }
245
+ });
246
+ ```
247
+
248
+ ## Requires (dependencies)
249
+ - Webex SDK service catalog and authenticated request API
250
+ - Browser WebSocket, Worker, URL and network-status APIs
251
+ - LoggerProxy and log upload
252
+
253
+ ## Requirements
254
+ | ID | WHAT | WHY | Source Evidence | Test / Example Evidence | Assumptions / Gaps | Confidence |
255
+ |---|---|---|---|---|---|---|
256
+ | CORE-R-001 | WebexRequest must delegate service/resource/method/body options to the authenticated host request API and return or reject with the host result unchanged. | All Contact Center REST clients share host-owned authentication and service routing without duplicating credential logic. | `src/services/core/WebexRequest.ts` | `test/unit/spec/services/core/WebexRequest.ts` | Authorization-header masking belongs to `AqmReqs` HTTP-failure handling, not `WebexRequest.request`. | PRESENT |
257
+ | CORE-R-002 | `initWebSocket` requires `{body: SubscribeRequest, resource: string}` and resolves only after WebSocket welcome or rejects on register/connect failure. | Subscription resource selection and readiness are required for a valid realtime session. | `src/services/core/websocket/WebSocketManager.ts` | `test/unit/spec/services/core/websocket/WebSocketManager.ts` | None; source and test evidence rechecked during the 2026-07-09 remediation; independent document revalidation pending. | PRESENT |
258
+ | CORE-R-003 | AqmReqs must be constructed with the primary WebSocket manager and settle generated request promises from `notifSuccess`/`notifFail` binds or `TIMEOUT_REQ`. | HTTP acknowledgement alone does not represent backend operation completion. | `src/services/core/aqm-reqs.ts` | `test/unit/spec/services/core/aqm-reqs.ts` | None; source and test evidence rechecked during the 2026-07-09 remediation; independent document revalidation pending. | PRESENT |
259
+ | CORE-R-004 | ConnectionService must emit transport-state details and retry `initWebSocket({body, resource})`; ContactCenter owns relogin policy. | Separating transport detection from agent recovery prevents Core from mutating package-level session state. | `src/services/core/websocket/connection-service.ts` | `test/unit/spec/services/core/websocket/connection-service.ts` | None; source and test evidence rechecked during the 2026-07-09 remediation; independent document revalidation pending. | PRESENT |
260
+ | CORE-R-005 | The keepalive worker must use the configured 4-second interval and 16-second close-socket timeout; AQM defaults to 20 seconds unless disabled/overridden. | Accurate timing is required for predictable recovery and request failure behavior. | `src/services/core/constants.ts` | `test/unit/spec/services/core/websocket/WebSocketManager.ts` | None; source and test evidence rechecked during the 2026-07-09 remediation; independent document revalidation pending. | PRESENT |
261
+ | CORE-R-006 | Treat Core timeout, keepalive, and recovery constants as fixed behavior controls, not rollout flags; Core owns no feature-gate evaluation. | Conflating operational constants with rollout policy could disable transport or correlation paths unexpectedly. | `src/services/core/constants.ts`, `src/services/index.ts` | `test/unit/spec/services/core/websocket/WebSocketManager.ts` | None; rollout applicability is explicitly N/A for Core. | PRESENT |
262
+ | CORE-R-007 | AQM routing-failure logging never emits the raw routing message payload or error verbatim; the failure-bind path logs only a fixed redacted diagnostic regardless of `redactSensitiveLogs`. When an AQM request additionally sets `redactSensitiveLogs`, timeout logs must also omit the request URL, bind key, and response while preserving settlement and cleanup behavior. | Dynamic request paths and routing messages can contain participant identifiers or phone numbers that must not enter diagnostic logs. | `src/services/core/aqm-reqs.ts`, `src/services/core/types.ts` | `test/unit/spec/services/core/aqm-reqs.ts` | The timeout flag is internal and opt-in; ordinary AQM logging remains backward compatible while routing-failure logging is unconditionally redacted. | PRESENT |
263
+ | CORE-R-008 | `WebSocketManager` opens a socket only for a subscribe/register `webSocketUrl` that parses as a `wss` URL whose host equals, or is a subdomain of, an entry in `ALLOWED_ROUTING_NOTIFS_DOMAINS`; a malformed, non-`wss`, or non-allow-listed URL is rejected with an error and no socket is opened. | A server-controlled subscribe response could otherwise direct the realtime connection to an untrusted or non-secure endpoint. | `src/services/core/websocket/WebSocketManager.ts`, `src/services/core/constants.ts` | `test/unit/spec/services/core/websocket/WebSocketManager.ts` | The allow-list is a fixed domain set; subdomain matching is exact suffix matching on the parsed hostname. | PRESENT |
264
+
265
+ ## Design Overview
266
+ Core separates four responsibilities:
267
+
268
+ 1. `WebexRequest` wraps the authenticated host request API and service-catalog routing.
269
+ 2. `WebSocketManager` registers a subscription using both `body` and `resource`, validates the returned `webSocketUrl` against the `ALLOWED_ROUTING_NOTIFS_DOMAINS` allow-list before connecting the socket, owns the keepalive worker, and emits raw messages/socket lifecycle events.
270
+ 3. `AqmReqs` registers bind matchers on the primary WebSocket, sends HTTP through WebexRequest, and settles requests only from matching notifications, HTTP failure, or timeout.
271
+ 4. `ConnectionService` observes message/socket liveness, emits connection-state details, and retries socket initialization. ContactCenter listens to those details and owns optional silent relogin.
272
+
273
+ ```typescript
274
+ const aqmReqs = new AqmReqs(webSocketManager);
275
+ const setState = aqmReqs.req((p: {data: Agent.StateChange}) => ({
276
+ host: WCC_API_GATEWAY,
277
+ url: '/v1/agents/session/state',
278
+ data: p.data,
279
+ method: HTTP_METHODS.PUT,
280
+ notifSuccess: {
281
+ bind: {
282
+ type: CC_EVENTS.AGENT_STATE_CHANGE,
283
+ data: {type: CC_EVENTS.AGENT_STATE_CHANGE_SUCCESS},
284
+ },
285
+ msg: {} as Agent.StateChangeSuccess,
286
+ },
287
+ notifFail: {
288
+ bind: {
289
+ type: CC_EVENTS.AGENT_STATE_CHANGE,
290
+ data: {type: CC_EVENTS.AGENT_STATE_CHANGE_FAILED},
291
+ },
292
+ errId: 'Service.aqm.agent.stateChange',
293
+ },
294
+ }));
295
+ await setState({data: stateChangePayload});
296
+ ```
297
+
298
+ `CLOSE_SOCKET_TIMEOUT` is 16000 ms. `CONNECTIVITY_CHECK_INTERVAL` drives reconnect attempts separately. `TIMEOUT_REQ` is the 20000 ms default AQM timeout; `WEBSOCKET_EVENT_TIMEOUT` is not the active AqmReqs default. Routing-failure diagnostics are always redacted to a fixed message that omits the raw payload and error. A request configuration may additionally set internal `redactSensitiveLogs: true` to redact timeout diagnostics (request URL, bind key, and response); neither redaction changes correlation, errors, timing, or cleanup.
299
+
300
+ ## Data Flow
301
+ ```mermaid
302
+ flowchart LR
303
+ Service[Agent/contact/dialer request] --> AQM[AqmReqs generated function]
304
+ AQM --> Bind[Register success/failure bind matchers]
305
+ AQM --> WR[WebexRequest authenticated HTTP]
306
+ WR --> Backend[WCC backend]
307
+ Backend --> Ack[HTTP acknowledgement]
308
+ Backend --> WS[Primary WebSocket notification]
309
+ WS --> Match{Bind matches?}
310
+ Match -->|success| Resolve[Resolve typed response]
311
+ Match -->|failure| Reject[Reject structured error]
312
+ Bind -->|TIMEOUT_REQ| Reject
313
+ ```
314
+
315
+ ```mermaid
316
+ flowchart TD
317
+ Message[WebSocket message] --> WSM[WebSocketManager emits message]
318
+ WSM --> CS[ConnectionService resets liveness timers]
319
+ CS --> Lost{Lost/recovered state changed?}
320
+ Lost -->|yes| Emit[Emit connectionLost details]
321
+ Emit --> CC[ContactCenter recovery policy]
322
+ SocketClose[Socket close] --> Retry[Retry every CONNECTIVITY_CHECK_INTERVAL]
323
+ Retry --> Init[initWebSocket body + SUBSCRIBE_API resource]
324
+ ```
325
+
326
+ ## Sequence Diagram(s)
327
+ Sequence coverage:
328
+
329
+ | Operation group | Diagram | Failure / recovery coverage |
330
+ |---|---|---|
331
+ | Authenticated REST | WebexRequest | Host/service rejection is propagated unchanged; AQM applies its own error mapping separately. |
332
+ | WebSocket subscribe/connect | Subscribe and connect | Register/connect rejection and welcome resolution. |
333
+ | AQM operation | Correlated request | Duplicate pending request, HTTP failure, failure bind, and timeout reject. |
334
+ | Reconnect | Connection recovery | Offline attempts retry on the next interval; restored and restore-failed states are emitted to ContactCenter. |
335
+
336
+ ### WebexRequest
337
+
338
+ ```mermaid
339
+ sequenceDiagram
340
+ participant Caller
341
+ participant WR as WebexRequest
342
+ participant Host as webex.request
343
+ participant API as WCC backend
344
+ Caller->>WR: request(service, resource, method, body)
345
+ WR->>Host: authenticated request(options)
346
+ Host->>API: HTTP request
347
+ alt success
348
+ API-->>Host: response
349
+ Host-->>WR: status/body/headers
350
+ WR-->>Caller: response
351
+ else host/service rejection
352
+ API-->>Host: error
353
+ Host-->>WR: same rejection
354
+ WR-->>Caller: same rejection
355
+ end
356
+ ```
357
+
358
+ ### Subscribe and connect
359
+
360
+ ```mermaid
361
+ sequenceDiagram
362
+ participant Caller
363
+ participant WSM as WebSocketManager
364
+ participant Host as webex.request
365
+ participant WS as Browser WebSocket
366
+ Caller->>WSM: initWebSocket({body, resource})
367
+ WSM->>Host: register(body, resource)
368
+ Host-->>WSM: WebSocket URL/subscription
369
+ WSM->>WSM: validate webSocketUrl against wss + allow-list
370
+ alt allow-listed wss URL
371
+ WSM->>WS: connect()
372
+ alt welcome
373
+ WS-->>WSM: Welcome event
374
+ WSM-->>Caller: WelcomeResponse
375
+ else connect failure
376
+ WSM-->>Caller: throw error
377
+ end
378
+ else malformed / non-wss / non-allow-listed URL
379
+ WSM-->>Caller: throw error (no socket opened)
380
+ end
381
+ ```
382
+
383
+ ### Correlated request
384
+
385
+ ```mermaid
386
+ sequenceDiagram
387
+ participant Caller
388
+ participant AQM as AqmReqs
389
+ participant WR as WebexRequest
390
+ participant WS as Primary WebSocket
391
+ Caller->>AQM: generated request(payload)
392
+ AQM->>AQM: install notifSuccess/notifFail matchers
393
+ alt matching pending request already exists and timeout is enabled
394
+ AQM-->>Caller: Service.aqm.reqs.Pending
395
+ else request accepted
396
+ AQM->>WR: request(config)
397
+ WR-->>AQM: HTTP acknowledgement only
398
+ alt success bind
399
+ WS-->>AQM: matching success notification
400
+ AQM-->>Caller: typed result
401
+ else failure bind or HTTP rejection
402
+ AQM-->>Caller: structured error
403
+ else timeout
404
+ AQM-->>Caller: Service.aqm.reqs.Timeout
405
+ end
406
+ end
407
+ ```
408
+
409
+ ### Connection recovery
410
+
411
+ ```mermaid
412
+ sequenceDiagram
413
+ participant WSM as WebSocketManager
414
+ participant CS as ConnectionService
415
+ participant CC as ContactCenter
416
+ WSM-->>CS: socketClose/message events
417
+ CS->>CS: update timers and reconnect state
418
+ alt browser online during retry interval
419
+ CS->>WSM: initWebSocket({body: subscribeRequest, resource: SUBSCRIBE_API})
420
+ WSM-->>CS: welcome/message
421
+ CS-->>CC: connectionLost({isSocketReconnected: true})
422
+ CC->>CC: decide whether to silentRelogin()
423
+ else browser offline or reconnect fails
424
+ CS->>CS: retain interval; retry on next CONNECTIVITY_CHECK_INTERVAL
425
+ opt recovery timeout expires
426
+ CS-->>CC: connectionLost({isRestoreFailed: true})
427
+ end
428
+ end
429
+ ```
430
+
431
+ ## Class / Component Relationships
432
+ ```mermaid
433
+ classDiagram
434
+ class WebexRequest
435
+ class WebSocketManager
436
+ class AqmReqs
437
+ class ConnectionService
438
+ class ContactCenter
439
+ AqmReqs --> WebexRequest : authenticated HTTP
440
+ AqmReqs --> WebSocketManager : bind-matched completion
441
+ ConnectionService --> WebSocketManager : liveness + reconnect
442
+ ConnectionService --> ContactCenter : connectionLost details
443
+ ContactCenter --> WebSocketManager : registration lifecycle
444
+ ```
445
+
446
+ ## Use Cases
447
+ - **UC-1 Authenticated REST:** pass the service key and request options to the host and return its response or rejection unchanged. Evidence: `src/services/core/WebexRequest.ts`, `test/unit/spec/services/core/WebexRequest.ts`.
448
+ - **UC-2 Subscribe/connect:** register with `{body, resource}`, connect, and wait for welcome. Evidence: `src/services/core/websocket/WebSocketManager.ts`, `test/unit/spec/services/core/websocket/WebSocketManager.ts`.
449
+ - **UC-3 AQM correlation:** send HTTP but settle on matching notification/failure/timeout. Evidence: `src/services/core/aqm-reqs.ts`, `test/unit/spec/services/core/aqm-reqs.ts`.
450
+ - **UC-4 Reconnect:** retry socket initialization and emit state for ContactCenter-owned recovery. Evidence: `src/services/core/websocket/connection-service.ts`, `test/unit/spec/services/core/websocket/connection-service.ts`.
451
+
452
+ ## State Model
453
+ WebSocketManager owns socket/welcome/worker state. AqmReqs owns pending success/failure/cancel bind maps until settlement or timeout. ConnectionService owns liveness/reconnect timers and flags, then emits state details. It does not own agent credentials, profile, or silent relogin.
454
+
455
+ ## Business Rules & Invariants
456
+ - Core must preserve its typed public/event contracts and must not invent backend states or responses. Enforced in `src/services/core/WebexRequest.ts`.
457
+ - A subscribe/register `webSocketUrl` is trusted only when it is a `wss` URL on the `ALLOWED_ROUTING_NOTIFS_DOMAINS` allow-list; otherwise `WebSocketManager` throws and never opens a socket. Enforced in `src/services/core/websocket/WebSocketManager.ts`.
458
+ - AQM routing-failure logs never contain the raw routing payload or error verbatim. Enforced in `src/services/core/aqm-reqs.ts`.
459
+ - Rollout applicability is N/A for Core: keepalive, timeout, and reconnect constants control behavior, while Services constructs Core without a feature gate.
460
+
461
+ ## Concurrency & Reactive Flow
462
+ The primary WebSocket fans messages to independent AqmReqs, ContactCenter, TaskManager, and ConnectionService listeners. AqmReqs clears all correlated bind entries on settlement. The keepalive worker posts status every 4000 ms and may request closure after 16000 ms offline; reconnect attempts use their separate interval. Listener registration/removal must preserve identity.
463
+
464
+ ## State Machine
465
+ ```mermaid
466
+ stateDiagram-v2
467
+ [*] --> SocketClosed
468
+ SocketClosed --> Connecting: initWebSocket(body, resource)
469
+ Connecting --> Connected: welcome
470
+ Connecting --> SocketClosed: register/connect error
471
+ Connected --> ConnectionSuspect: liveness timer expires
472
+ ConnectionSuspect --> Reconnecting: socket close / retry
473
+ Reconnecting --> Connected: reconnect + message
474
+ Reconnecting --> Reconnecting: offline or retry failure
475
+ Connected --> SocketClosed: manual close
476
+ ```
477
+
478
+ ## Protocol / Wire Format
479
+ `WebSocketManager.initWebSocket` accepts `{body: SubscribeRequest, resource: string}`. Subscription uses the host Webex request API; the returned `webSocketUrl` must be a `wss` URL on the `ALLOWED_ROUTING_NOTIFS_DOMAINS` allow-list or the socket is not opened. AqmReqs operational HTTP uses the WebexRequest wrapper. AQM request configs carry `host`, `url`, optional `method`/`data`, `notifSuccess.bind`, optional `notifFail.bind`, optional cancel bind, and optional timeout. HTTP acknowledgement never substitutes for the matching WebSocket operation result.
480
+
481
+ ## Error Handling & Failure Modes
482
+ | Condition | Signal (error/code/result) | Caller recovery |
483
+ |---|---|---|
484
+ | Dependency rejection | Typed/rethrown error or failure event | Inspect structured details, preserve tracking id, and retry only when the operation is safe. |
485
+ | Timeout or missing async completion | Timeout/recovery state | Follow the module-specific recovery path; never synthesize success. |
486
+
487
+ Standard error handler for SDK operations:
488
+
489
+ ```typescript
490
+ import {getErrorDetails} from './services/core/Utils';
491
+
492
+ try {
493
+ await operation();
494
+ } catch (error) {
495
+ const {error: detailedError, reason} = getErrorDetails(
496
+ error,
497
+ 'methodName', // Method name for logging
498
+ 'ModuleName' // Module name for logging
499
+ );
500
+
501
+ // getErrorDetails automatically:
502
+ // 1. Logs the error
503
+ // 2. Uploads logs (unless AGENT_NOT_FOUND in silentRelogin)
504
+ // 3. Extracts reason from error.details
505
+ // 4. Creates Error with reason as message
506
+
507
+ throw detailedError;
508
+ }
509
+ ```
510
+
511
+ Error handler for task operations:
512
+
513
+ ```typescript
514
+ import {generateTaskErrorObject} from './services/core/Utils';
515
+
516
+ try {
517
+ await taskOperation();
518
+ } catch (error) {
519
+ const taskError = generateTaskErrorObject(
520
+ error,
521
+ 'transfer',
522
+ 'TaskModule'
523
+ );
524
+ throw taskError;
525
+ }
526
+ ```
527
+
528
+ A specific `Msg<T>` for failure responses. Access error details via `failure.data`:
529
+
530
+ ```typescript
531
+ export type Failure = Msg<{
532
+ agentId: string;
533
+ trackingId: string;
534
+ reasonCode: number;
535
+ orgId: string;
536
+ reason: string;
537
+ }>;
538
+
539
+ // Usage in catch
540
+ const failure = error.details as Failure;
541
+ LoggerProxy.error(`Operation failed: ${failure.data?.reason}`, {
542
+ module: 'MyService',
543
+ method: 'myMethod',
544
+ trackingId: failure?.trackingId,
545
+ });
546
+ ```
547
+
548
+ Error interface with a flexible data field for additional context:
549
+
550
+ ```typescript
551
+ export interface AugmentedError extends Error {
552
+ data?: Record<string, any>;
553
+ }
554
+ ```
555
+
556
+ ```typescript
557
+ import * as Err from './Err';
558
+
559
+ const error = new Err.Details('Service.aqm.agent.login', {
560
+ status: 401,
561
+ type: 'UNAUTHORIZED',
562
+ trackingId: 'uuid',
563
+ });
564
+ ```
565
+
566
+ ```typescript
567
+ import {createErrDetailsObject} from './Utils';
568
+
569
+ const errDetails = createErrDetailsObject(webexRequestPayload);
570
+ // Returns Err.Details with trackingId and body
571
+ ```
572
+
573
+ ```typescript
574
+ // Correct
575
+ const {error: detailedError} = getErrorDetails(error, method, module);
576
+ throw detailedError;
577
+
578
+ // Wrong - loses context
579
+ throw error;
580
+ ```
581
+
582
+ This section documents shared error helpers in `Utils.ts` that normalize errors, enrich them with context, and ensure consistent logging/upload behavior across services.
583
+
584
+ ```typescript
585
+ // Msg - Generic message interface (GlobalTypes.ts)
586
+ export type Msg<T = any> = {
587
+ type: string;
588
+ orgId: string;
589
+ trackingId: string;
590
+ data: T;
591
+ };
592
+
593
+ // Failure - Backend error structure (GlobalTypes.ts)
594
+ // Built on Msg<T> with specific error data fields
595
+ export type Failure = Msg<{
596
+ agentId: string;
597
+ trackingId: string;
598
+ reasonCode: number;
599
+ orgId: string;
600
+ reason: string;
601
+ }>;
602
+
603
+ // AugmentedError - Extended Error with flexible data field (GlobalTypes.ts)
604
+ export interface AugmentedError extends Error {
605
+ data?: Record<string, any>;
606
+ }
607
+ ```
608
+
609
+ ```mermaid
610
+ flowchart TD
611
+ A[Error caught] --> B[Cast error.details to Failure]
612
+ B --> C[Extract reason from failure.data.reason]
613
+ C --> D{Is silentRelogin + AGENT_NOT_FOUND?}
614
+ D -->|Yes| E[Skip logging/upload]
615
+ D -->|No| F[Log error with LoggerProxy]
616
+ F --> G[Upload logs via WebexRequest]
617
+ G --> H[Check if stationLogin]
618
+ H -->|Yes| I[Get field-specific error data]
619
+ H -->|No| J[Use generic error]
620
+ I --> K[Create Error with data property]
621
+ J --> K
622
+ K --> L["Return {error, reason}"]
623
+ ```
624
+
625
+ Use this helper for agent/config-style flows where backend failure payloads are transformed into a user-facing `Error` plus `reason`, with optional station-login field metadata.
626
+
627
+ ```typescript
628
+ export const getErrorDetails = (error: any, methodName: string, moduleName: string) => {
629
+ let errData = {message: '', fieldName: ''};
630
+
631
+ const failure = error.details as Failure;
632
+ const reason = failure?.data?.reason ?? `Error while performing ${methodName}`;
633
+
634
+ // Log error (unless AGENT_NOT_FOUND in silentRelogin)
635
+ if (!(reason === 'AGENT_NOT_FOUND' && methodName === 'silentRelogin')) {
636
+ LoggerProxy.error(`${methodName} failed with reason: ${reason}`, {
637
+ module: moduleName,
638
+ method: methodName,
639
+ trackingId: failure?.trackingId,
640
+ });
641
+
642
+ // Upload logs
643
+ WebexRequest.getInstance().uploadLogs({
644
+ correlationId: failure?.trackingId,
645
+ });
646
+ }
647
+
648
+ // For stationLogin, extract field-specific error data (message + fieldName)
649
+ if (methodName === 'stationLogin') {
650
+ errData = getStationLoginErrorData(failure, error.loginOption);
651
+ }
652
+
653
+ const err = new Error(reason);
654
+ // @ts-ignore - custom property for backward compatibility
655
+ err.data = errData;
656
+
657
+ return {error: err, reason};
658
+ };
659
+ ```
660
+
661
+ Use this helper for task/interaction flows where richer task error metadata (`errorType`, `errorData`, `reasonCode`, `trackingId`) is required on the returned `AugmentedError`.
662
+
663
+ ```typescript
664
+ export const generateTaskErrorObject = (
665
+ error: any,
666
+ methodName: string,
667
+ moduleName: string
668
+ ): AugmentedError => {
669
+ const trackingId = error?.details?.trackingId || error?.trackingId || '';
670
+ const errorMsg = error?.details?.msg;
671
+
672
+ const errorMessage = errorMsg?.errorMessage || error.message || 'Error';
673
+ const errorType = errorMsg?.errorType || error.name || 'Unknown Error';
674
+ const errorData = errorMsg?.errorData || '';
675
+ const reasonCode = errorMsg?.reasonCode || 0;
676
+
677
+ LoggerProxy.error(`${methodName} failed: ${errorMessage} (${errorType})`, {
678
+ module: moduleName,
679
+ method: methodName,
680
+ trackingId,
681
+ });
682
+ WebexRequest.getInstance().uploadLogs({correlationId: trackingId});
683
+
684
+ const reason = `${errorType}: ${errorMessage}${errorData ? ` (${errorData})` : ''}`;
685
+ const err: AugmentedError = new Error(reason);
686
+ err.data = {
687
+ message: errorMessage,
688
+ errorType,
689
+ errorData,
690
+ reasonCode,
691
+ trackingId,
692
+ };
693
+
694
+ return err;
695
+ };
696
+ ```
697
+
698
+ ```typescript
699
+ // Use getErrorDetails for:
700
+ // - Agent service operations
701
+ // - Station login/logout flows
702
+ //
703
+ // Use generateTaskErrorObject for:
704
+ // - Task service operations
705
+ // - Interaction-related errors
706
+ ```
707
+
708
+ **Cause**: Subscribe API failed or invalid URL
709
+
710
+ **Solution**: Check subscribe response and WebSocket URL
711
+
712
+ **Cause**: Event listener not registered
713
+
714
+ **Solution**: Ensure `on('message', handler)` called before connect
715
+
716
+ **Cause**: Keepalive not enabled or network issues
717
+
718
+ **Solution**: Verify worker-driven keepalive is running after socket `onopen`, and check network/offline transitions
719
+
720
+ ## Pitfalls
721
+ - `initWebSocket` requires both `body` and `resource`; omitting `resource` registers against no durable subscription endpoint.
722
+ - AqmReqs installs notification binds before HTTP and never resolves from acknowledgement; duplicate binds, timeout, and cleanup ordering are correctness-critical.
723
+ - AQM routing-failure logs are always redacted; sensitive AQM configurations must also use the opt-in `redactSensitiveLogs` flag so dynamic URLs and responses are not included in timeout logs.
724
+ - Do not open the WebSocket directly from a subscribe/register response; the `webSocketUrl` must first pass `wss` scheme and allow-listed host validation.
725
+ - Keepalive closure (16 seconds), lost-connection detection (8 seconds), reconnect interval (5 seconds), and recovery timeout (50 seconds) are separate controls and must not be conflated.
726
+
727
+ ## Module Do's / Don'ts
728
+ - DO keep authentication and service resolution in the host Webex request layer; `WebexRequest.request` is a thin delegating wrapper.
729
+ - DO mask authorization headers in the `AqmReqs` HTTP-error/timeout paths before those details are logged or surfaced.
730
+ - DO enable `redactSensitiveLogs` for AQM requests whose dynamic URL or event payload can contain identity/PII.
731
+ - DO clear success/failure/cancel bind entries together when an AQM request settles.
732
+ - DON'T move silent-relogin policy into ConnectionService; it emits transport state only.
733
+ - DON'T treat timeout constants as feature flags or reuse one timer for another lifecycle purpose.
734
+
735
+ ```typescript
736
+ const response = await webexReq.request({...});
737
+
738
+ if (response.statusCode !== 200) {
739
+ throw new Error(`API call failed with ${response.statusCode}`);
740
+ }
741
+ ```
742
+
743
+ ```typescript
744
+ const trackingId = response.headers?.trackingid ||
745
+ response.headers?.TrackingID;
746
+ ```
747
+
748
+ ## Key Design Trade-off
749
+ - Request initiation stays HTTP while completion can arrive asynchronously over WebSocket; explicit timers and correlation preserve backend fidelity but increase lifecycle complexity.
750
+
751
+ ## Test-Case Strategy (module)
752
+ Unit tests mirror module paths under `test/unit/spec/services/core`. Preserve positive and negative paths, event ordering, timeout/recovery behavior, and the package's 85% global branch/function/line/statement threshold.
753
+
754
+ | Behavior / Requirement | Existing test evidence | Gap |
755
+ |---|---|---|
756
+ | `CORE-R-001` | `test/unit/spec/services/core/WebexRequest.ts` | None. |
757
+ | `CORE-R-002` | `test/unit/spec/services/core/websocket/WebSocketManager.ts` | None. |
758
+ | `CORE-R-003` | `test/unit/spec/services/core/aqm-reqs.ts` | None. |
759
+ | `CORE-R-004` | `test/unit/spec/services/core/websocket/connection-service.ts` | None. |
760
+ | `CORE-R-005` | `test/unit/spec/services/core/websocket/WebSocketManager.ts` | Keep timer-value assertions synchronized with constants. |
761
+ | `CORE-R-006` | `test/unit/spec/services/core/websocket/WebSocketManager.ts` | Feature-gate absence is verified from construction/source rather than a dedicated negative test. |
762
+ | `CORE-R-007` | `test/unit/spec/services/core/aqm-reqs.ts` | None. |
763
+ | `CORE-R-008` | `test/unit/spec/services/core/websocket/WebSocketManager.ts` | None. |
764
+
765
+ ## Traceability
766
+ - Repo architecture: `../../../../ai-docs/ARCHITECTURE.md` · Registry: `../../../../ai-docs/SPEC_INDEX.md`
767
+ - Coverage state and contracts baseline: `../../../../.sdd/manifest.json`
768
+
769
+ - [Root Orchestrator AGENTS.md](../../../../AGENTS.md) - Task routing, critical rules, cross-service patterns
770
+
771
+ - [WebSocketManager.ts](../websocket/WebSocketManager.ts)
772
+
773
+ - [WebexRequest.ts](../WebexRequest.ts)
774
+
775
+ - [Utils.ts](../Utils.ts)
776
+
777
+ - [GlobalTypes.ts](../GlobalTypes.ts)
778
+
779
+ - [Root Orchestrator AGENTS.md](../../../../AGENTS.md) — Task routing, critical rules, cross-service patterns
780
+
781
+ - [WebSocketManager.ts](../websocket/WebSocketManager.ts) — WebSocket lifecycle, keepalive worker integration
782
+
783
+ - [connection-service.ts](../websocket/connection-service.ts) — Reconnection logic, connection state events
784
+
785
+ - [keepalive.worker.js](../websocket/keepalive.worker.js) — Web Worker for periodic keepalive and offline detection
786
+
787
+ - [WebexRequest.ts](../WebexRequest.ts) — Singleton HTTP request handler
788
+
789
+ - [Utils.ts](../Utils.ts) — `getErrorDetails`, `generateTaskErrorObject`, consult utilities
790
+
791
+ - [Err.ts](../Err.ts) — `Err.Message` and `Err.Details` error classes
792
+
793
+ - [aqm-reqs.ts](../aqm-reqs.ts) — AQM request/response pattern, WebSocket notification binding
794
+
795
+ - [GlobalTypes.ts](../GlobalTypes.ts) — `Msg`, `Failure`, `AugmentedError` type definitions
796
+
797
+ - [types.ts](../types.ts) — `Pending`, `Req`, `Conf`, `Res` types for AqmReqs