@webex/contact-center 3.12.0-next.9 → 3.12.0-next.90

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 (229) hide show
  1. package/.sdd/manifest.json +876 -0
  2. package/AGENTS.md +94 -0
  3. package/ai-docs/ARCHITECTURE.md +168 -0
  4. package/ai-docs/CONTRACTS.md +46 -0
  5. package/ai-docs/GETTING_STARTED.md +168 -0
  6. package/ai-docs/GLOSSARY.md +43 -0
  7. package/ai-docs/README.md +138 -0
  8. package/ai-docs/REVIEW_CHECKLIST.md +41 -0
  9. package/ai-docs/RULES.md +444 -0
  10. package/ai-docs/SECURITY.md +52 -0
  11. package/ai-docs/SERVICE_STATE.md +48 -0
  12. package/ai-docs/SPEC_INDEX.md +65 -0
  13. package/ai-docs/adr/0001-spec-source-policy.md +55 -0
  14. package/ai-docs/adr/README.md +8 -0
  15. package/ai-docs/adr/_adr-template.md +31 -0
  16. package/ai-docs/contact-center-spec.md +341 -0
  17. package/ai-docs/features/generated-spec-conformance-fidelity-remediation/spec/feature-spec.md +117 -0
  18. package/ai-docs/features/residual-warning-coverage-completion/spec/feature-spec.md +203 -0
  19. package/ai-docs/features/validator-code-fidelity-drift-fix/spec/feature-spec.md +315 -0
  20. package/ai-docs/patterns/event-driven-patterns.md +485 -0
  21. package/ai-docs/patterns/testing-patterns.md +480 -0
  22. package/ai-docs/patterns/typescript-patterns.md +365 -0
  23. package/ai-docs/templates/README.md +102 -0
  24. package/ai-docs/templates/documentation/create-agents-md.md +240 -0
  25. package/ai-docs/templates/documentation/create-architecture-md.md +295 -0
  26. package/ai-docs/templates/existing-service/bug-fix.md +254 -0
  27. package/ai-docs/templates/existing-service/feature-enhancement.md +450 -0
  28. package/ai-docs/templates/new-method/00-master.md +80 -0
  29. package/ai-docs/templates/new-method/01-requirements.md +232 -0
  30. package/ai-docs/templates/new-method/02-implementation.md +295 -0
  31. package/ai-docs/templates/new-method/03-tests.md +201 -0
  32. package/ai-docs/templates/new-method/04-validation.md +141 -0
  33. package/ai-docs/templates/new-service/00-master.md +109 -0
  34. package/ai-docs/templates/new-service/01-pre-questions.md +159 -0
  35. package/ai-docs/templates/new-service/02-code-generation.md +346 -0
  36. package/ai-docs/templates/new-service/03-integration.md +178 -0
  37. package/ai-docs/templates/new-service/04-test-generation.md +205 -0
  38. package/ai-docs/templates/new-service/05-validation.md +145 -0
  39. package/dist/cc.js +265 -29
  40. package/dist/cc.js.map +1 -1
  41. package/dist/config.js +6 -0
  42. package/dist/config.js.map +1 -1
  43. package/dist/constants.js +17 -1
  44. package/dist/constants.js.map +1 -1
  45. package/dist/index.js +20 -5
  46. package/dist/index.js.map +1 -1
  47. package/dist/metrics/behavioral-events.js +101 -0
  48. package/dist/metrics/behavioral-events.js.map +1 -1
  49. package/dist/metrics/constants.js +25 -4
  50. package/dist/metrics/constants.js.map +1 -1
  51. package/dist/services/ApiAiAssistant.js +153 -8
  52. package/dist/services/ApiAiAssistant.js.map +1 -1
  53. package/dist/services/UserPreference.js +427 -0
  54. package/dist/services/UserPreference.js.map +1 -0
  55. package/dist/services/config/Util.js +3 -3
  56. package/dist/services/config/Util.js.map +1 -1
  57. package/dist/services/config/constants.js +23 -2
  58. package/dist/services/config/constants.js.map +1 -1
  59. package/dist/services/config/types.js +49 -9
  60. package/dist/services/config/types.js.map +1 -1
  61. package/dist/services/core/Err.js.map +1 -1
  62. package/dist/services/core/Utils.js +107 -32
  63. package/dist/services/core/Utils.js.map +1 -1
  64. package/dist/services/core/websocket/WebSocketManager.js +2 -1
  65. package/dist/services/core/websocket/WebSocketManager.js.map +1 -1
  66. package/dist/services/core/websocket/types.js.map +1 -1
  67. package/dist/services/index.js +1 -1
  68. package/dist/services/index.js.map +1 -1
  69. package/dist/services/task/Task.js +688 -0
  70. package/dist/services/task/Task.js.map +1 -0
  71. package/dist/services/task/TaskFactory.js +45 -0
  72. package/dist/services/task/TaskFactory.js.map +1 -0
  73. package/dist/services/task/TaskManager.js +728 -527
  74. package/dist/services/task/TaskManager.js.map +1 -1
  75. package/dist/services/task/TaskUtils.js +162 -26
  76. package/dist/services/task/TaskUtils.js.map +1 -1
  77. package/dist/services/task/constants.js +9 -2
  78. package/dist/services/task/constants.js.map +1 -1
  79. package/dist/services/task/dialer.js +78 -0
  80. package/dist/services/task/dialer.js.map +1 -1
  81. package/dist/services/task/digital/Digital.js +77 -0
  82. package/dist/services/task/digital/Digital.js.map +1 -0
  83. package/dist/services/task/state-machine/TaskStateMachine.js +837 -0
  84. package/dist/services/task/state-machine/TaskStateMachine.js.map +1 -0
  85. package/dist/services/task/state-machine/actions.js +543 -0
  86. package/dist/services/task/state-machine/actions.js.map +1 -0
  87. package/dist/services/task/state-machine/constants.js +161 -0
  88. package/dist/services/task/state-machine/constants.js.map +1 -0
  89. package/dist/services/task/state-machine/guards.js +340 -0
  90. package/dist/services/task/state-machine/guards.js.map +1 -0
  91. package/dist/services/task/state-machine/index.js +53 -0
  92. package/dist/services/task/state-machine/index.js.map +1 -0
  93. package/dist/services/task/state-machine/types.js +54 -0
  94. package/dist/services/task/state-machine/types.js.map +1 -0
  95. package/dist/services/task/state-machine/uiControlsComputer.js +553 -0
  96. package/dist/services/task/state-machine/uiControlsComputer.js.map +1 -0
  97. package/dist/services/task/taskDataNormalizer.js +99 -0
  98. package/dist/services/task/taskDataNormalizer.js.map +1 -0
  99. package/dist/services/task/types.js +212 -4
  100. package/dist/services/task/types.js.map +1 -1
  101. package/dist/services/task/voice/Voice.js +1042 -0
  102. package/dist/services/task/voice/Voice.js.map +1 -0
  103. package/dist/services/task/voice/WebRTC.js +149 -0
  104. package/dist/services/task/voice/WebRTC.js.map +1 -0
  105. package/dist/types/cc.d.ts +94 -1
  106. package/dist/types/config.d.ts +6 -0
  107. package/dist/types/constants.d.ts +17 -1
  108. package/dist/types/index.d.ts +21 -6
  109. package/dist/types/metrics/constants.d.ts +21 -1
  110. package/dist/types/services/ApiAiAssistant.d.ts +22 -4
  111. package/dist/types/services/UserPreference.d.ts +118 -0
  112. package/dist/types/services/config/constants.d.ts +21 -0
  113. package/dist/types/services/config/types.d.ts +171 -10
  114. package/dist/types/services/core/Err.d.ts +4 -0
  115. package/dist/types/services/core/Utils.d.ts +33 -13
  116. package/dist/types/services/core/websocket/WebSocketManager.d.ts +1 -0
  117. package/dist/types/services/core/websocket/types.d.ts +1 -1
  118. package/dist/types/services/index.d.ts +1 -1
  119. package/dist/types/services/task/Task.d.ts +157 -0
  120. package/dist/types/services/task/TaskFactory.d.ts +12 -0
  121. package/dist/types/services/task/TaskUtils.d.ts +46 -2
  122. package/dist/types/services/task/constants.d.ts +7 -0
  123. package/dist/types/services/task/dialer.d.ts +30 -0
  124. package/dist/types/services/task/digital/Digital.d.ts +22 -0
  125. package/dist/types/services/task/state-machine/TaskStateMachine.d.ts +1144 -0
  126. package/dist/types/services/task/state-machine/actions.d.ts +10 -0
  127. package/dist/types/services/task/state-machine/constants.d.ts +107 -0
  128. package/dist/types/services/task/state-machine/guards.d.ts +90 -0
  129. package/dist/types/services/task/state-machine/index.d.ts +13 -0
  130. package/dist/types/services/task/state-machine/types.d.ts +267 -0
  131. package/dist/types/services/task/state-machine/uiControlsComputer.d.ts +9 -0
  132. package/dist/types/services/task/taskDataNormalizer.d.ts +10 -0
  133. package/dist/types/services/task/types.d.ts +603 -66
  134. package/dist/types/services/task/voice/Voice.d.ts +184 -0
  135. package/dist/types/services/task/voice/WebRTC.d.ts +53 -0
  136. package/dist/types/types.d.ts +135 -0
  137. package/dist/types/webex.d.ts +1 -0
  138. package/dist/types.js +118 -2
  139. package/dist/types.js.map +1 -1
  140. package/dist/webex.js +14 -2
  141. package/dist/webex.js.map +1 -1
  142. package/package.json +15 -12
  143. package/src/cc.ts +329 -30
  144. package/src/config.ts +6 -0
  145. package/src/constants.ts +17 -1
  146. package/src/index.ts +23 -5
  147. package/src/metrics/ai-docs/AGENTS.md +350 -0
  148. package/src/metrics/ai-docs/ARCHITECTURE.md +338 -0
  149. package/src/metrics/ai-docs/metrics-spec.md +854 -0
  150. package/src/metrics/behavioral-events.ts +106 -0
  151. package/src/metrics/constants.ts +27 -4
  152. package/src/services/ApiAiAssistant.ts +203 -8
  153. package/src/services/UserPreference.ts +509 -0
  154. package/src/services/agent/ai-docs/AGENTS.md +240 -0
  155. package/src/services/agent/ai-docs/ARCHITECTURE.md +304 -0
  156. package/src/services/agent/ai-docs/agent-spec.md +504 -0
  157. package/src/services/ai-docs/AGENTS.md +386 -0
  158. package/src/services/ai-docs/services-spec.md +492 -0
  159. package/src/services/config/Util.ts +3 -3
  160. package/src/services/config/ai-docs/AGENTS.md +255 -0
  161. package/src/services/config/ai-docs/ARCHITECTURE.md +426 -0
  162. package/src/services/config/ai-docs/config-spec.md +669 -0
  163. package/src/services/config/constants.ts +25 -1
  164. package/src/services/config/types.ts +174 -11
  165. package/src/services/core/Err.ts +2 -0
  166. package/src/services/core/Utils.ts +123 -37
  167. package/src/services/core/ai-docs/AGENTS.md +381 -0
  168. package/src/services/core/ai-docs/ARCHITECTURE.md +698 -0
  169. package/src/services/core/ai-docs/core-spec.md +783 -0
  170. package/src/services/core/websocket/WebSocketManager.ts +2 -0
  171. package/src/services/core/websocket/types.ts +1 -1
  172. package/src/services/index.ts +1 -1
  173. package/src/services/task/Task.ts +837 -0
  174. package/src/services/task/TaskFactory.ts +55 -0
  175. package/src/services/task/TaskManager.ts +739 -614
  176. package/src/services/task/TaskUtils.ts +205 -25
  177. package/src/services/task/ai-docs/AGENTS.md +457 -0
  178. package/src/services/task/ai-docs/ARCHITECTURE.md +594 -0
  179. package/src/services/task/ai-docs/task-spec.md +1319 -0
  180. package/src/services/task/constants.ts +7 -0
  181. package/src/services/task/dialer.ts +80 -0
  182. package/src/services/task/digital/Digital.ts +95 -0
  183. package/src/services/task/state-machine/TaskStateMachine.ts +1077 -0
  184. package/src/services/task/state-machine/actions.ts +685 -0
  185. package/src/services/task/state-machine/ai-docs/AGENTS.md +458 -0
  186. package/src/services/task/state-machine/ai-docs/ARCHITECTURE.md +1137 -0
  187. package/src/services/task/state-machine/ai-docs/task-state-machine-spec.md +2115 -0
  188. package/src/services/task/state-machine/constants.ts +172 -0
  189. package/src/services/task/state-machine/guards.ts +406 -0
  190. package/src/services/task/state-machine/index.ts +28 -0
  191. package/src/services/task/state-machine/types.ts +241 -0
  192. package/src/services/task/state-machine/uiControlsComputer.ts +867 -0
  193. package/src/services/task/taskDataNormalizer.ts +137 -0
  194. package/src/services/task/types.ts +710 -71
  195. package/src/services/task/voice/Voice.ts +1267 -0
  196. package/src/services/task/voice/WebRTC.ts +187 -0
  197. package/src/types.ts +166 -2
  198. package/src/utils/AGENTS.md +278 -0
  199. package/src/utils/ai-docs/utils-spec.md +381 -0
  200. package/src/webex.js +2 -0
  201. package/test/unit/spec/cc.ts +343 -23
  202. package/test/unit/spec/logger-proxy.ts +70 -0
  203. package/test/unit/spec/services/ApiAiAssistant.ts +178 -20
  204. package/test/unit/spec/services/UserPreference.ts +401 -0
  205. package/test/unit/spec/services/WebCallingService.ts +7 -1
  206. package/test/unit/spec/services/config/index.ts +30 -30
  207. package/test/unit/spec/services/core/Utils.ts +425 -8
  208. package/test/unit/spec/services/core/websocket/WebSocketManager.ts +66 -40
  209. package/test/unit/spec/services/task/AutoWrapup.ts +63 -0
  210. package/test/unit/spec/services/task/Task.ts +477 -0
  211. package/test/unit/spec/services/task/TaskFactory.ts +62 -0
  212. package/test/unit/spec/services/task/TaskManager.ts +834 -1704
  213. package/test/unit/spec/services/task/TaskUtils.ts +206 -0
  214. package/test/unit/spec/services/task/dialer.ts +190 -0
  215. package/test/unit/spec/services/task/digital/Digital.ts +105 -0
  216. package/test/unit/spec/services/task/state-machine/TaskStateMachine.ts +1825 -0
  217. package/test/unit/spec/services/task/state-machine/guards.ts +479 -0
  218. package/test/unit/spec/services/task/state-machine/types.ts +18 -0
  219. package/test/unit/spec/services/task/state-machine/uiControlsComputer.ts +2020 -0
  220. package/test/unit/spec/services/task/taskTestUtils.ts +87 -0
  221. package/test/unit/spec/services/task/voice/Voice.ts +631 -0
  222. package/test/unit/spec/services/task/voice/WebRTC.ts +235 -0
  223. package/umd/contact-center.min.js +2 -2
  224. package/umd/contact-center.min.js.map +1 -1
  225. package/dist/services/task/index.js +0 -1525
  226. package/dist/services/task/index.js.map +0 -1
  227. package/dist/types/services/task/index.d.ts +0 -650
  228. package/src/services/task/index.ts +0 -1801
  229. package/test/unit/spec/services/task/index.ts +0 -2184
@@ -0,0 +1,381 @@
1
+ # Utils — 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 | `utils` |
10
+ | Source path(s) | `src/utils` |
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
+ Utils is one of nine confirmed Contact Center SDK modules. Own shared pagination contracts and the bounded in-memory page cache used by Contact Center data services. Existing reviewed documentation is migrated by meaning and code/tests remain the behavioral referee.
27
+
28
+ The utils scope currently provides shared pagination and cache behavior for contact-center data services:
29
+
30
+ - **Typed Pagination Contracts**: Reusable interfaces for response metadata and query params
31
+
32
+ - **Generic In-Memory Page Caching**: `PageCache<T>` utility for simple pagination reuse
33
+
34
+ - **Cache Safety Rules**: Explicit bypass behavior for search/filter/sort scenarios
35
+
36
+ - **Spec-Driven Utility Workflow**: Utility-specific implementation and validation flow documented inline in this file
37
+
38
+ | Component | File | Description |
39
+ |---|---|---|
40
+ | `PageCache` | [`PageCache.ts`](../PageCache.ts) | Generic in-memory cache utility for paginated API responses with TTL expiry and helper methods for key generation and cache eligibility checks. |
41
+ | `Pagination Types` | [`PageCache.ts`](../PageCache.ts) | `PaginationMeta`, `PaginatedResponse<T>`, `BaseSearchParams`, and `PageCacheEntry<T>` shared across data services. |
42
+ | `Pagination Defaults` | [`PageCache.ts`](../PageCache.ts) | `PAGINATION_DEFAULTS` (`PAGE`, `PAGE_SIZE`) used by services for consistent request defaults. |
43
+ | `Specs Workflow` | `ai-docs/utils-spec.md` | Canonical flow for spec-driven utility changes, acceptance criteria, and drift checks. |
44
+
45
+ ## Purpose / Responsibility
46
+ Own shared pagination contracts and the bounded in-memory page cache used by Contact Center data services.
47
+
48
+ ## Stack
49
+ TypeScript 5.4 generics, in-memory Map/clock, LoggerProxy, Jest consumer tests.
50
+
51
+ ## Folder / Package Structure
52
+ ```text
53
+ src/utils/
54
+ ├── AGENTS.md
55
+ ├── PageCache.ts
56
+ ```
57
+
58
+ ```text
59
+ src/utils/
60
+ ├── AGENTS.md # Preserved legacy, noncanonical utils guide
61
+ └── PageCache.ts # Generic cache + pagination contracts/defaults
62
+ ```
63
+
64
+ ## Key Files (source of truth)
65
+ | File | Holds |
66
+ |---|---|
67
+ | `src/utils/PageCache.ts` | Authoritative PageCache implementation plus pagination/cache contracts and defaults. |
68
+ | `src/types.ts` | Package-wide public response/search types that consume PageCache contracts; not a Utils implementation. |
69
+ | `src/services/AddressBook.ts` | Services-layer PageCache consumer. |
70
+ | `src/services/EntryPoint.ts` | Services-layer PageCache consumer. |
71
+ | `src/services/Queue.ts` | Services-layer PageCache consumer. |
72
+
73
+ ## Public Surface
74
+ | Surface | Availability | Source |
75
+ |---|---|---|
76
+ | `PageCache<T>` | exported from the Utils module file for internal service use; not re-exported by package root | `src/utils/PageCache.ts` |
77
+ | `PaginationMeta`, `PaginatedResponse<T>`, `BaseSearchParams` | exported by PageCache module and consumed by package-wide types | `src/utils/PageCache.ts`, `src/types.ts` |
78
+ | `PAGINATION_DEFAULTS`, `PageCacheEntry<T>`, `CacheValidationParams` | PageCache module exports; not package-root exports | `src/utils/PageCache.ts` |
79
+ | AddressBook/EntryPoint/Queue public response/search aliases | package-root exports whose definitions indirectly use PageCache contracts | `src/types.ts`, `src/index.ts` |
80
+
81
+ No claim is made that `src/types.ts`, AddressBook, EntryPoint, or Queue is implemented by Utils.
82
+
83
+ ## Requires (dependencies)
84
+ - LoggerProxy
85
+ - In-memory Map and wall clock
86
+ - AddressBook, EntryPoint, and Queue consumers
87
+
88
+ ## Requirements
89
+ | ID | WHAT | WHY | Source Evidence | Test / Example Evidence | Assumptions / Gaps | Confidence |
90
+ |---|---|---|---|---|---|---|
91
+ | UTILS-R-001 | Use cache only for simple pagination requests without search, filter, attributes, or sortBy. | Parameterized queries cannot safely reuse a page keyed only by scope/page/pageSize. | `src/utils/PageCache.ts` | `test/unit/spec/services/AddressBook.ts` | None; source and test evidence rechecked during the 2026-07-09 remediation; independent document revalidation pending. | PRESENT |
92
+ | UTILS-R-002 | Build cache keys from a caller-defined `scopeId` plus `page:pageSize`: `orgId` for EntryPoint/Queue and `bookId` for AddressBook. | Consumer scope and page boundaries prevent cross-scope or cross-page reuse. | `src/utils/PageCache.ts`, `src/services/AddressBook.ts`, `src/services/EntryPoint.ts`, `src/services/Queue.ts` | `test/unit/spec/services/AddressBook.ts`, `test/unit/spec/services/EntryPoint.ts`, `test/unit/spec/services/Queue.ts` | `PageCache.buildCacheKey` names its first implementation parameter `orgId`, but runtime callers establish the broader `scopeId` semantics. | PRESENT |
93
+ | UTILS-R-003 | Expire entries after the configured five-minute TTL and delete them on stale lookup. | Bounded staleness prevents indefinite reuse of remote service data. | `src/utils/PageCache.ts` | None | Direct fake-clock expiration coverage is absent from current consumer tests. | PRESENT |
94
+ | UTILS-R-004 | Cache data with total-page/record metadata and allow owning consumers to clear the cache. | Paginated services need consistent metadata without transferring ownership of remote records to the SDK. | `src/utils/PageCache.ts` | `test/unit/spec/services/AddressBook.ts` | Cache hit/miss and metadata are exercised through consumers; `clearCache()` has no direct assertion. | PRESENT |
95
+ | UTILS-R-005 | Accept already-fetched page values from consuming services and never store or process credentials; use the consumer's scope value only as part of the in-memory key. | Authentication remains in Services/Core and scope-separated keys prevent unrelated pages from colliding. | `src/utils/PageCache.ts`, `src/services/core/WebexRequest.ts`, `src/services/AddressBook.ts`, `src/services/EntryPoint.ts`, `src/services/Queue.ts` | `test/unit/spec/services/AddressBook.ts` | None; security/auth ownership is explicit. | PRESENT |
96
+ | UTILS-R-006 | Keep PageCache free of rollout flags; consuming services decide whether to invoke it and query parameters determine cache eligibility. | Cache correctness must depend on request shape, not hidden deployment state. | `src/utils/PageCache.ts` | `test/unit/spec/services/AddressBook.ts`, `test/unit/spec/services/Queue.ts` | None; rollout applicability is explicitly N/A. | PRESENT |
97
+
98
+ ## Design Overview
99
+ Utils separates its stable consumption boundary from collaborators so ownership and failure behavior stay explicit. Caching is intentionally limited to simple page browsing; search/filter/sort requests bypass cache to prevent incorrect reuse.
100
+
101
+ > **This is the authoritative documentation for the `src/utils` scope.** It covers shared pagination/cache contracts used by data services. For task routing and cross-service conventions, see the [root orchestrator AGENTS.md](../../../AGENTS.md).
102
+
103
+ Current consumers of `PageCache` and defaults:
104
+
105
+ | Consumer | File | Usage |
106
+ |---|---|---|
107
+ | `AddressBook` | [`../../services/AddressBook.ts`](../../services/AddressBook.ts) | Caches paged address-book responses |
108
+ | `EntryPoint` | [`../../services/EntryPoint.ts`](../../services/EntryPoint.ts) | Caches paged entry-point responses |
109
+ | `Queue` | [`../../services/Queue.ts`](../../services/Queue.ts) | Caches paged queue responses |
110
+ | `Public type contracts` | [`../../types.ts`](../../types.ts) | Re-exports pagination/search contracts into SDK-facing types |
111
+
112
+ Cross-scope mention:
113
+
114
+ - Services-layer docs reference utils caching contracts at [`../../services/ai-docs/services-spec.md`](../../services/ai-docs/services-spec.md).
115
+
116
+ ## Data Flow
117
+ ```mermaid
118
+ flowchart LR
119
+ Service[AddressBook / EntryPoint / Queue] --> Eligible{canUseCache params?}
120
+ Eligible -->|search/filter/attributes/sort present| Backend[Fetch without cache]
121
+ Eligible -->|simple pagination| Key[buildCacheKey scopeId:page:pageSize]
122
+ Key --> Lookup[getCachedPage]
123
+ Lookup -->|fresh| Hit[Return cached page]
124
+ Lookup -->|missing or TTL expired| Backend
125
+ Backend --> Fetched{cache eligible and response has data?}
126
+ Fetched -->|yes| Store[cachePage data + total metadata]
127
+ Fetched -->|no| Result[Return uncached response]
128
+ Store --> Result
129
+ ```
130
+
131
+ ## Sequence Diagram(s)
132
+ Sequence coverage:
133
+
134
+ | Operation group | Diagram | Failure / recovery coverage |
135
+ |---|---|---|
136
+ | Eligible lookup, fetch, and store | Cache lifecycle | Advanced queries bypass cache; misses and expired entries fetch from the backend; failed backend calls never reach `cachePage`. |
137
+ | Explicit cache clearing | Clear all entries | `clearCache` removes all entries from that consumer-owned PageCache instance and logs the prior size. |
138
+
139
+ ### Cache lifecycle
140
+
141
+ ```mermaid
142
+ sequenceDiagram
143
+ participant Service as Data service
144
+ participant Cache as PageCache
145
+ participant API as Backend API
146
+ Service->>Cache: canUseCache(params)
147
+ alt simple pagination
148
+ Note over Service,Cache: scopeId = bookId (AddressBook) or orgId (EntryPoint/Queue)
149
+ Service->>Cache: buildCacheKey(scopeId, page, pageSize)
150
+ Service->>Cache: getCachedPage(key)
151
+ alt fresh hit
152
+ Cache-->>Service: PageCacheEntry
153
+ else miss or expired
154
+ Service->>API: fetch page
155
+ alt backend success with response data
156
+ API-->>Service: data + meta
157
+ Service->>Cache: cachePage(key, data, meta)
158
+ else backend rejection
159
+ API--xService: error
160
+ Note over Service,Cache: no cache write
161
+ else success without data
162
+ API-->>Service: response without data
163
+ Note over Service,Cache: return response without a cache write
164
+ end
165
+ end
166
+ else advanced query
167
+ Service->>API: fetch without cache
168
+ end
169
+ ```
170
+
171
+ ### Clear all entries
172
+
173
+ ```mermaid
174
+ sequenceDiagram
175
+ participant Owner as Consumer service
176
+ participant Cache as Its PageCache instance
177
+ participant Log as LoggerProxy
178
+ Owner->>Cache: clearCache()
179
+ Cache->>Cache: capture size, then Map.clear()
180
+ Cache->>Log: log cleared entry count
181
+ Cache-->>Owner: void
182
+ ```
183
+
184
+ ## Class / Component Relationships
185
+ ```mermaid
186
+ classDiagram
187
+ class PageCache~T~ {
188
+ +canUseCache(params) boolean
189
+ +buildCacheKey(scopeId, page, pageSize) string
190
+ +getCachedPage(key) PageCacheEntry
191
+ +cachePage(key, data, meta)
192
+ +clearCache()
193
+ +getCacheSize() number
194
+ }
195
+ class AddressBook
196
+ class EntryPoint
197
+ class Queue
198
+ AddressBook --> PageCache : consumes
199
+ EntryPoint --> PageCache : consumes
200
+ Queue --> PageCache : consumes
201
+ ```
202
+
203
+ ## Use Cases
204
+ - **UC-1 Cache eligibility:** AddressBook, EntryPoint, or Queue bypasses cache whenever search, filter, attributes, or sort is supplied. Evidence: `src/utils/PageCache.ts`, `test/unit/spec/services/AddressBook.ts`.
205
+ - **UC-2 Cache-key construction:** a simple page lookup uses `<scopeId>:page:pageSize`; AddressBook supplies `bookId`, while EntryPoint and Queue supply `orgId`. Evidence: `src/utils/PageCache.ts`, `src/services/AddressBook.ts`, `src/services/EntryPoint.ts`, `src/services/Queue.ts`.
206
+ - **UC-3 TTL lookup/expiry:** a fresh cached entry is returned; an expired entry is deleted and treated as a miss. Evidence: `src/utils/PageCache.ts`; no direct expiration test currently exists.
207
+ - **UC-4 Page insertion and clearing:** successful page data and normalized totals are cached, while `clearCache()` removes all entries for that service instance. Evidence: `src/utils/PageCache.ts`; consumer tests cover insertion/hit behavior, but not direct clearing.
208
+
209
+ ## State Model
210
+ Utils retains only in-memory runtime state. Durable domain records remain owned by remote Webex services. State changes are driven by explicit calls, events, timers, or actor transitions documented below.
211
+
212
+ `PageCache<T>` provides a consistent caching model for paginated list APIs. It is optimized for simple page browsing and intentionally bypasses cache for parameterized query cases (`search`, `filter`, `attributes`, `sortBy`).
213
+
214
+ ```typescript
215
+ import PageCache, {PAGINATION_DEFAULTS} from '../utils/PageCache';
216
+
217
+ const cache = new PageCache<MyItem>('MyService');
218
+
219
+ const page = PAGINATION_DEFAULTS.PAGE;
220
+ const pageSize = PAGINATION_DEFAULTS.PAGE_SIZE;
221
+ // AddressBook uses bookId; EntryPoint and Queue use orgId.
222
+ const scopeId = bookIdOrOrgId;
223
+ const cacheKey = cache.buildCacheKey(scopeId, page, pageSize);
224
+
225
+ // Include sortBy only for services that support sorting.
226
+ const canUseCache = cache.canUseCache({search, filter, attributes, sortBy});
227
+
228
+ if (canUseCache) {
229
+ const cachedEntry = cache.getCachedPage(cacheKey);
230
+ if (cachedEntry) {
231
+ return {
232
+ data: cachedEntry.data,
233
+ meta: {
234
+ page,
235
+ pageSize,
236
+ ...cachedEntry.totalMeta,
237
+ },
238
+ };
239
+ }
240
+ }
241
+
242
+ const response = await fetchPageFromApi();
243
+
244
+ if (canUseCache && response.data) {
245
+ cache.cachePage(cacheKey, response.data, response.meta);
246
+ }
247
+
248
+ return response;
249
+ ```
250
+
251
+ ```mermaid
252
+ graph TD
253
+ A[Request arrives with scopeId/page/pageSize] --> B{canUseCache?}
254
+ B -->|No: search/filter/attributes/sortBy provided| C[Bypass cache and call API]
255
+ B -->|Yes| D[buildCacheKey scopeId:page:pageSize]
256
+ D --> E["getCachedPage(cacheKey)"]
257
+ E -->|Miss| C
258
+ E -->|Hit and not expired| F[Return cached data and totalMeta]
259
+ E -->|Hit but expired >= 5 minutes| G[Delete entry and treat as miss]
260
+ G --> C
261
+ C --> H[Receive API response]
262
+ H --> K{canUseCache and response has data?}
263
+ K -->|Yes| I["cachePage(cacheKey, data, meta)"]
264
+ K -->|No| J[Return uncached response]
265
+ I --> J[Return fresh response]
266
+ ```
267
+
268
+ Creates a typed cache instance and stores `apiName` for `LoggerProxy` context.
269
+
270
+ Returns `true` only when all of these are absent:
271
+
272
+ - `search`
273
+
274
+ - `filter`
275
+
276
+ - `attributes`
277
+
278
+ - `sortBy`
279
+
280
+ `sortOrder` alone does not trigger cache bypass because `CacheValidationParams` currently keys bypass on fields that materially change the query result set in existing consumers.
281
+
282
+ Builds deterministic cache key format:
283
+
284
+ ```text
285
+ ${scopeId}:${page}:${pageSize}
286
+ ```
287
+
288
+ The implementation parameter is named `orgId`, but its value is the caller-defined `scopeId`: `bookId` in AddressBook and `orgId` in EntryPoint/Queue.
289
+
290
+ Behavior:
291
+
292
+ 1. Returns `null` if key not found
293
+
294
+ 2. Computes cache age in minutes
295
+
296
+ 3. If age is `>= 5`, logs expiry, deletes entry, returns `null`
297
+
298
+ 4. Otherwise returns cached entry
299
+
300
+ Stores entry with:
301
+
302
+ - `data`
303
+
304
+ - `timestamp`
305
+
306
+ - `totalMeta.totalPages`
307
+
308
+ - `totalMeta.totalRecords` mapped from `meta.totalRecords || meta.totalItems`
309
+
310
+ Clears all entries and logs cleared entry count.
311
+
312
+ Returns current in-memory entry count.
313
+
314
+ Note: `clearCache()` and `getCacheSize()` are available for future use and are not currently called by existing consumers.
315
+
316
+ ## Business Rules & Invariants
317
+ - Utils must preserve its typed public/event contracts and must not invent backend states or responses. Enforced in `src/utils/PageCache.ts`.
318
+ - Security/auth applicability is limited to scope separation: PageCache receives already-fetched values, owns no credentials, and includes its caller-supplied scope value in cache keys.
319
+ - Rollout applicability is N/A: PageCache has no feature flag; consumers choose whether to use it and `canUseCache` decides eligibility from query parameters.
320
+
321
+ ## Pitfalls
322
+ - Do not describe the first cache-key field as universally `orgId`: AddressBook passes `bookId`, while EntryPoint and Queue pass `orgId`.
323
+ - Do not cache queries containing `search`, `filter`, `attributes`, or `sortBy`; their result set is not represented in the key.
324
+ - Do not treat an expired entry as usable data. `getCachedPage` deletes it and returns `null`.
325
+ - Do not cache a rejected request or a response without data; only the consuming service owns the backend request and decides when to call `cachePage`.
326
+
327
+ ## Module Do's / Don'ts
328
+ - DO create a separate `PageCache` instance per consuming service and pass that consumer's stable scope value into `buildCacheKey`.
329
+ - DO preserve the five-minute `>=` expiry boundary and the `totalRecords || totalItems` compatibility mapping.
330
+ - DO keep credentials, request execution, and backend-error handling in the consuming service/Core layers.
331
+ - DON'T add query dimensions without either extending the cache key or making `canUseCache` bypass them.
332
+ - DON'T claim `clearCache()` or TTL expiry is directly unit-tested until dedicated assertions exist.
333
+
334
+ When changing `src/utils` behavior or contracts:
335
+
336
+ 1. Follow the workflow diagram below
337
+
338
+ 2. Define acceptance criteria for contract and runtime behavior
339
+
340
+ 3. Verify cache TTL, bypass rules, and key schema
341
+
342
+ 4. Validate no spec drift before shipping
343
+
344
+ ```mermaid
345
+ flowchart TD
346
+ A[Change proposed in src/utils] --> B{Classify change scope}
347
+ B -->|Contract change| C[Document expected API/type behavior]
348
+ B -->|Runtime behavior change| D[Document cache behavior and TTL impact]
349
+ B -->|Both| C
350
+ C --> E[Update canonical utils-spec contracts and consumer map]
351
+ D --> F[Validate cache key schema and bypass conditions]
352
+ E --> G[Run drift check against PageCache.ts and consumer services]
353
+ F --> G
354
+ G --> H{Behavior and docs aligned?}
355
+ H -->|No| I[Revise implementation/docs and re-validate]
356
+ I --> G
357
+ H -->|Yes| J[Prepare PR with acceptance criteria and evidence]
358
+ ```
359
+
360
+ ## Key Design Trade-off
361
+ - Caching is intentionally limited to simple page browsing; search/filter/sort requests bypass cache to prevent incorrect reuse.
362
+
363
+ ## Test-Case Strategy (module)
364
+ PageCache has no dedicated unit file; current consumer tests in `test/unit/spec/services/AddressBook.ts`, `EntryPoint.ts`, and `Queue.ts` cover request shaping plus cache hit/miss behavior. Add direct PageCache tests for the five-minute expiry boundary, entry deletion, metadata normalization, clearing, and key construction with both `bookId` and `orgId` scope values.
365
+
366
+ | Behavior / Requirement | Existing test evidence | Gap |
367
+ |---|---|---|
368
+ | `UTILS-R-001` | AddressBook, EntryPoint, and Queue consumer tests exercise advanced query parameters and simple pagination. | Add a direct `canUseCache` table test for each bypass field and `sortOrder` alone. |
369
+ | `UTILS-R-002` | AddressBook repeat/miss tests exercise `bookId`-scoped caching; EntryPoint and Queue miss tests exercise `orgId` consumers. | Add direct key-string assertions for both runtime scope kinds. |
370
+ | `UTILS-R-003` | None. | Add fake-clock tests at just below and exactly five minutes, including deletion. |
371
+ | `UTILS-R-004` | AddressBook verifies a repeat-call hit and response metadata; all three consumers verify misses. | Add direct metadata fallback and `clearCache`/`getCacheSize` assertions. |
372
+ | `UTILS-R-005` | Source inspection confirms PageCache has no credential or request dependency. | No runtime credential test is needed; retain the static ownership check. |
373
+ | `UTILS-R-006` | Source inspection confirms no feature-flag dependency; consumer tests cover invocation choices. | No direct rollout test is applicable. |
374
+
375
+ ## Traceability
376
+ - Repo architecture: `../../../ai-docs/ARCHITECTURE.md` · Registry: `../../../ai-docs/SPEC_INDEX.md`
377
+ - Coverage state and contracts baseline: `../../../.sdd/manifest.json`
378
+
379
+ - [Root orchestrator AGENTS.md](../../../AGENTS.md) - Task routing and critical package rules
380
+
381
+ - [PageCache implementation](../PageCache.ts)
package/src/webex.js CHANGED
@@ -10,6 +10,8 @@ import './index';
10
10
 
11
11
  import config from './webex-config';
12
12
 
13
+ export * from './index';
14
+
13
15
  /**
14
16
  * Ensures global Buffer is defined, which is required for SDK functionality in some environments.
15
17
  * @ignore