@talkpilot/core-db 1.3.65 → 1.3.66

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (322) hide show
  1. package/.cursor/rules/development.mdc +65 -65
  2. package/AGENTS.md +49 -49
  3. package/DEVELOPMENT.md +141 -141
  4. package/README.md +48 -0
  5. package/dist/talkpilot/auditLogs/auditLogs.getters.d.ts +8 -0
  6. package/dist/talkpilot/auditLogs/auditLogs.getters.d.ts.map +1 -0
  7. package/dist/talkpilot/auditLogs/auditLogs.getters.js +26 -0
  8. package/dist/talkpilot/auditLogs/auditLogs.getters.js.map +1 -0
  9. package/dist/talkpilot/auditLogs/auditLogs.setters.d.ts +3 -0
  10. package/dist/talkpilot/auditLogs/auditLogs.setters.d.ts.map +1 -0
  11. package/dist/talkpilot/auditLogs/auditLogs.setters.js +9 -0
  12. package/dist/talkpilot/auditLogs/auditLogs.setters.js.map +1 -0
  13. package/dist/talkpilot/auditLogs/auditLogs.types.d.ts +11 -0
  14. package/dist/talkpilot/auditLogs/auditLogs.types.d.ts.map +1 -0
  15. package/dist/talkpilot/auditLogs/auditLogs.types.js +3 -0
  16. package/dist/talkpilot/auditLogs/auditLogs.types.js.map +1 -0
  17. package/dist/talkpilot/auditLogs/index.d.ts +3 -0
  18. package/dist/talkpilot/auditLogs/index.d.ts.map +1 -0
  19. package/dist/talkpilot/auditLogs/index.js +19 -0
  20. package/dist/talkpilot/auditLogs/index.js.map +1 -0
  21. package/dist/talkpilot/calls/calls.constants.d.ts +9 -1
  22. package/dist/talkpilot/calls/calls.constants.d.ts.map +1 -1
  23. package/dist/talkpilot/calls/calls.constants.js +9 -1
  24. package/dist/talkpilot/calls/calls.constants.js.map +1 -1
  25. package/dist/talkpilot/calls/calls.getters.d.ts +7 -1
  26. package/dist/talkpilot/calls/calls.getters.d.ts.map +1 -1
  27. package/dist/talkpilot/calls/calls.getters.js +181 -1
  28. package/dist/talkpilot/calls/calls.getters.js.map +1 -1
  29. package/dist/talkpilot/calls/calls.types.d.ts +35 -0
  30. package/dist/talkpilot/calls/calls.types.d.ts.map +1 -1
  31. package/dist/talkpilot/clientDeletionLogs/clientDeletionLogs.getters.d.ts +4 -0
  32. package/dist/talkpilot/clientDeletionLogs/clientDeletionLogs.getters.d.ts.map +1 -0
  33. package/dist/talkpilot/clientDeletionLogs/clientDeletionLogs.getters.js +9 -0
  34. package/dist/talkpilot/clientDeletionLogs/clientDeletionLogs.getters.js.map +1 -0
  35. package/dist/talkpilot/clientDeletionLogs/clientDeletionLogs.setters.d.ts +3 -0
  36. package/dist/talkpilot/clientDeletionLogs/clientDeletionLogs.setters.d.ts.map +1 -0
  37. package/dist/talkpilot/clientDeletionLogs/clientDeletionLogs.setters.js +9 -0
  38. package/dist/talkpilot/clientDeletionLogs/clientDeletionLogs.setters.js.map +1 -0
  39. package/dist/talkpilot/clientDeletionLogs/clientDeletionLogs.types.d.ts +10 -0
  40. package/dist/talkpilot/clientDeletionLogs/clientDeletionLogs.types.d.ts.map +1 -0
  41. package/dist/talkpilot/clientDeletionLogs/clientDeletionLogs.types.js +3 -0
  42. package/dist/talkpilot/clientDeletionLogs/clientDeletionLogs.types.js.map +1 -0
  43. package/dist/talkpilot/clientDeletionLogs/index.d.ts +4 -0
  44. package/dist/talkpilot/clientDeletionLogs/index.d.ts.map +1 -0
  45. package/dist/talkpilot/clientDeletionLogs/index.js +20 -0
  46. package/dist/talkpilot/clientDeletionLogs/index.js.map +1 -0
  47. package/dist/talkpilot/clients/clients.constants.d.ts +3 -0
  48. package/dist/talkpilot/clients/clients.constants.d.ts.map +1 -0
  49. package/dist/talkpilot/clients/clients.constants.js +6 -0
  50. package/dist/talkpilot/clients/clients.constants.js.map +1 -0
  51. package/dist/talkpilot/clients/clients.getters.d.ts +2 -0
  52. package/dist/talkpilot/clients/clients.getters.d.ts.map +1 -1
  53. package/dist/talkpilot/clients/clients.getters.js +15 -1
  54. package/dist/talkpilot/clients/clients.getters.js.map +1 -1
  55. package/dist/talkpilot/clients/clients.lifecycle.d.ts +10 -0
  56. package/dist/talkpilot/clients/clients.lifecycle.d.ts.map +1 -0
  57. package/dist/talkpilot/clients/clients.lifecycle.js +95 -0
  58. package/dist/talkpilot/clients/clients.lifecycle.js.map +1 -0
  59. package/dist/talkpilot/clients/clients.types.d.ts +21 -0
  60. package/dist/talkpilot/clients/clients.types.d.ts.map +1 -1
  61. package/dist/talkpilot/clients/index.d.ts +2 -0
  62. package/dist/talkpilot/clients/index.d.ts.map +1 -1
  63. package/dist/talkpilot/clients/index.js +2 -0
  64. package/dist/talkpilot/clients/index.js.map +1 -1
  65. package/dist/talkpilot/flows/flows.schema.d.ts +0 -6
  66. package/dist/talkpilot/flows/flows.schema.d.ts.map +1 -1
  67. package/dist/talkpilot/flows/flows.schema.js +0 -2
  68. package/dist/talkpilot/flows/flows.schema.js.map +1 -1
  69. package/dist/talkpilot/flows/flows.types.d.ts +0 -1
  70. package/dist/talkpilot/flows/flows.types.d.ts.map +1 -1
  71. package/dist/talkpilot/index.d.ts +1 -0
  72. package/dist/talkpilot/index.d.ts.map +1 -1
  73. package/dist/talkpilot/index.js +1 -0
  74. package/dist/talkpilot/index.js.map +1 -1
  75. package/dist/talkpilot/phone_numbers/phone_numbers.getter.d.ts +9 -1
  76. package/dist/talkpilot/phone_numbers/phone_numbers.getter.d.ts.map +1 -1
  77. package/dist/talkpilot/phone_numbers/phone_numbers.getter.js +66 -1
  78. package/dist/talkpilot/phone_numbers/phone_numbers.getter.js.map +1 -1
  79. package/dist/talkpilot/phone_numbers/phone_numbers.types.d.ts +5 -0
  80. package/dist/talkpilot/phone_numbers/phone_numbers.types.d.ts.map +1 -1
  81. package/dist/talkpilot/results/results.constants.d.ts +4 -0
  82. package/dist/talkpilot/results/results.constants.d.ts.map +1 -0
  83. package/dist/talkpilot/results/results.constants.js +10 -0
  84. package/dist/talkpilot/results/results.constants.js.map +1 -0
  85. package/dist/talkpilot/results/results.statistics.getters.d.ts +12 -0
  86. package/dist/talkpilot/results/results.statistics.getters.d.ts.map +1 -0
  87. package/dist/talkpilot/results/results.statistics.getters.js +258 -0
  88. package/dist/talkpilot/results/results.statistics.getters.js.map +1 -0
  89. package/dist/talkpilot/results/results.statistics.types.d.ts +22 -0
  90. package/dist/talkpilot/results/results.statistics.types.d.ts.map +1 -0
  91. package/dist/talkpilot/results/results.statistics.types.js +3 -0
  92. package/dist/talkpilot/results/results.statistics.types.js.map +1 -0
  93. package/dist/test-utils/factories/index.d.ts +2 -0
  94. package/dist/test-utils/factories/index.d.ts.map +1 -1
  95. package/dist/test-utils/factories/index.js +2 -0
  96. package/dist/test-utils/factories/index.js.map +1 -1
  97. package/dist/test-utils/factories/talkpilot/clients.d.ts +14 -0
  98. package/dist/test-utils/factories/talkpilot/clients.d.ts.map +1 -0
  99. package/dist/test-utils/factories/talkpilot/clients.js +19 -0
  100. package/dist/test-utils/factories/talkpilot/clients.js.map +1 -0
  101. package/dist/test-utils/factories/talkpilot/results.d.ts +16 -0
  102. package/dist/test-utils/factories/talkpilot/results.d.ts.map +1 -0
  103. package/dist/test-utils/factories/talkpilot/results.js +40 -0
  104. package/dist/test-utils/factories/talkpilot/results.js.map +1 -0
  105. package/jest.config.js +20 -20
  106. package/package.json +46 -46
  107. package/src/__tests__/setup.ts +20 -20
  108. package/src/bulkWrite/__tests__/bulkWrite.spec.ts +65 -65
  109. package/src/bulkWrite/bulkWrite.ops.ts +45 -45
  110. package/src/bulkWrite/bulkWrite.types.ts +4 -4
  111. package/src/bulkWrite/index.ts +2 -2
  112. package/src/config.ts +9 -9
  113. package/src/configuration/index.ts +17 -17
  114. package/src/configuration/internalModels/index.ts +3 -3
  115. package/src/configuration/internalModels/internalModels.constants.ts +1 -1
  116. package/src/configuration/internalModels/internalModels.getters.ts +33 -33
  117. package/src/configuration/internalModels/internalModels.types.ts +12 -12
  118. package/src/configuration/models/__tests__/models.getters.spec.ts +67 -67
  119. package/src/configuration/models/index.ts +27 -27
  120. package/src/configuration/models/models.constants.ts +15 -15
  121. package/src/configuration/models/models.getters.ts +71 -71
  122. package/src/configuration/models/models.types.ts +80 -80
  123. package/src/configuration/mongodb-client.ts +62 -62
  124. package/src/configuration/prompts/index.ts +2 -2
  125. package/src/configuration/prompts/prompts.getters.ts +49 -49
  126. package/src/configuration/prompts/prompts.types.ts +11 -11
  127. package/src/connection.ts +81 -81
  128. package/src/index.ts +47 -47
  129. package/src/municipal/__tests__/validation.spec.ts +62 -62
  130. package/src/municipal/cities/cities.getters.ts +50 -50
  131. package/src/municipal/cities/cities.types.ts +11 -11
  132. package/src/municipal/cities/index.ts +2 -2
  133. package/src/municipal/departmentsSubjects/__tests__/departmentsSubjects.spec.ts +272 -272
  134. package/src/municipal/departmentsSubjects/departmentsSubjects.getters.ts +317 -317
  135. package/src/municipal/departmentsSubjects/departmentsSubjects.types.ts +73 -73
  136. package/src/municipal/departmentsSubjects/index.ts +9 -9
  137. package/src/municipal/index.ts +22 -22
  138. package/src/municipal/mongodb-client.ts +61 -61
  139. package/src/municipal/muniIssues/__tests__/muniIssues.setters.spec.ts +94 -94
  140. package/src/municipal/muniIssues/__tests__/muniIssues.setup.spec.ts +92 -92
  141. package/src/municipal/muniIssues/index.ts +17 -17
  142. package/src/municipal/muniIssues/muniIssues.constants.ts +18 -18
  143. package/src/municipal/muniIssues/muniIssues.getters.ts +24 -24
  144. package/src/municipal/muniIssues/muniIssues.schema.ts +66 -66
  145. package/src/municipal/muniIssues/muniIssues.setters.ts +24 -24
  146. package/src/municipal/muniIssues/muniIssues.setup.ts +65 -65
  147. package/src/municipal/muniIssues/muniIssues.types.ts +37 -37
  148. package/src/municipal/streets/__tests__/streets.spec.ts +253 -253
  149. package/src/municipal/streets/index.ts +2 -2
  150. package/src/municipal/streets/streets.getters.ts +140 -140
  151. package/src/municipal/streets/streets.types.ts +19 -19
  152. package/src/municipal/systemInstructions/__tests__/getters.spec.ts +113 -113
  153. package/src/municipal/systemInstructions/__tests__/setters.spec.ts +274 -274
  154. package/src/municipal/systemInstructions/index.ts +7 -7
  155. package/src/municipal/systemInstructions/instructions.getters.ts +57 -57
  156. package/src/municipal/systemInstructions/instructions.setters.ts +119 -119
  157. package/src/municipal/systemInstructions/instructions.types.ts +30 -30
  158. package/src/municipal/tickets/__tests__/tickets.getters.spec.ts +30 -30
  159. package/src/municipal/tickets/__tests__/tickets.statistics.spec.ts +99 -99
  160. package/src/municipal/tickets/index.ts +9 -9
  161. package/src/municipal/tickets/tickets.constants.ts +8 -8
  162. package/src/municipal/tickets/tickets.getters.ts +121 -121
  163. package/src/municipal/tickets/tickets.statistics.aggregation.ts +110 -110
  164. package/src/municipal/tickets/tickets.statistics.getters.ts +145 -145
  165. package/src/municipal/tickets/tickets.types.ts +54 -54
  166. package/src/municipal/utils/types.ts +11 -11
  167. package/src/talkpilot/__tests__/db.spec.ts +38 -38
  168. package/src/talkpilot/__tests__/mongodb-client.spec.ts +18 -18
  169. package/src/talkpilot/__tests__/validation.spec.ts +68 -68
  170. package/src/talkpilot/agents/__tests__/agents.getters.spec.ts +29 -29
  171. package/src/talkpilot/agents/agents.getters.ts +34 -34
  172. package/src/talkpilot/agents/agents.types.ts +14 -14
  173. package/src/talkpilot/agents/index.ts +2 -2
  174. package/src/talkpilot/auditLogs/__tests__/auditLogs.spec.ts +91 -0
  175. package/src/talkpilot/auditLogs/auditLogs.getters.ts +26 -0
  176. package/src/talkpilot/auditLogs/auditLogs.types.ts +12 -0
  177. package/src/talkpilot/auditLogs/index.ts +2 -0
  178. package/src/talkpilot/backgroundToolResults/__tests__/backgroundToolResults.getters.spec.ts +147 -147
  179. package/src/talkpilot/backgroundToolResults/backgroundToolResults.getters.ts +65 -65
  180. package/src/talkpilot/backgroundToolResults/backgroundToolResults.types.ts +23 -23
  181. package/src/talkpilot/backgroundToolResults/index.ts +2 -2
  182. package/src/talkpilot/calls/__tests__/callStats.utils.spec.ts +128 -128
  183. package/src/talkpilot/calls/__tests__/calls.dashboard.spec.ts +229 -229
  184. package/src/talkpilot/calls/__tests__/calls.spec.ts +471 -471
  185. package/src/talkpilot/calls/__tests__/calls.statistics.getters.spec.ts +374 -0
  186. package/src/talkpilot/calls/__tests__/calls.statistics.spec.ts +483 -483
  187. package/src/talkpilot/calls/calls.constants.ts +61 -49
  188. package/src/talkpilot/calls/calls.getters.ts +270 -1
  189. package/src/talkpilot/calls/calls.statistics.getters.ts +668 -668
  190. package/src/talkpilot/calls/calls.statistics.types.ts +48 -48
  191. package/src/talkpilot/calls/calls.types.ts +40 -0
  192. package/src/talkpilot/calls/dashboard/calls.dashboard.ts +295 -295
  193. package/src/talkpilot/calls/dashboard/calls.dashboard.types.ts +57 -57
  194. package/src/talkpilot/calls/index.ts +6 -6
  195. package/src/talkpilot/clientAudioBuffers/__tests__/clientAudioBuffer.getters.spec.ts +160 -160
  196. package/src/talkpilot/clientAudioBuffers/clientAudioBuffer.getters.ts +117 -117
  197. package/src/talkpilot/clientAudioBuffers/clientsAudioBuffers.types.ts +25 -25
  198. package/src/talkpilot/clientAudioBuffers/index.ts +2 -2
  199. package/src/talkpilot/clients/__tests__/clients.getters.spec.ts +51 -0
  200. package/src/talkpilot/clients/__tests__/clients.lifecycle.spec.ts +166 -0
  201. package/src/talkpilot/clients/__tests__/clients.quota.spec.ts +123 -123
  202. package/src/talkpilot/clients/clients.constants.ts +2 -0
  203. package/src/talkpilot/clients/clients.getters.ts +32 -19
  204. package/src/talkpilot/clients/clients.lifecycle.ts +116 -0
  205. package/src/talkpilot/clients/clients.quota.getters.ts +119 -119
  206. package/src/talkpilot/clients/clients.quota.types.ts +27 -27
  207. package/src/talkpilot/clients/clients.types.ts +37 -18
  208. package/src/talkpilot/clients/index.ts +6 -4
  209. package/src/talkpilot/clientsConfig/__tests__/clientsConfig.getters.spec.ts +423 -423
  210. package/src/talkpilot/clientsConfig/__tests__/clientsConfig.spec.ts +212 -212
  211. package/src/talkpilot/clientsConfig/clientsConfig.constants.ts +2 -2
  212. package/src/talkpilot/clientsConfig/clientsConfig.getters.ts +247 -247
  213. package/src/talkpilot/clientsConfig/clientsConfig.types.ts +137 -137
  214. package/src/talkpilot/clientsConfig/index.ts +3 -3
  215. package/src/talkpilot/contextNotes/__tests__/contextNotes.getters.spec.ts +217 -217
  216. package/src/talkpilot/contextNotes/contextNotes.getters.ts +85 -85
  217. package/src/talkpilot/contextNotes/contextNotes.types.ts +20 -20
  218. package/src/talkpilot/contextNotes/index.ts +2 -2
  219. package/src/talkpilot/flows/__tests__/flows.schema.spec.ts +124 -142
  220. package/src/talkpilot/flows/flows.getter.ts +34 -34
  221. package/src/talkpilot/flows/flows.schema.ts +180 -182
  222. package/src/talkpilot/flows/flows.types.ts +211 -212
  223. package/src/talkpilot/flows/index.ts +7 -7
  224. package/src/talkpilot/groups/__tests__/groups.spec.ts +90 -90
  225. package/src/talkpilot/groups/__tests__/phone.utils.spec.ts +32 -32
  226. package/src/talkpilot/groups/groups.getters.ts +30 -30
  227. package/src/talkpilot/groups/groups.types.ts +29 -29
  228. package/src/talkpilot/groups/index.ts +3 -3
  229. package/src/talkpilot/groups/phone.utils.ts +46 -46
  230. package/src/talkpilot/index.ts +32 -31
  231. package/src/talkpilot/leads/index.ts +2 -2
  232. package/src/talkpilot/leads/leads.getter.ts +6 -6
  233. package/src/talkpilot/leads/leads.schema.ts +33 -33
  234. package/src/talkpilot/leads/leads.types.ts +20 -20
  235. package/src/talkpilot/mongodb-client.ts +78 -78
  236. package/src/talkpilot/phone_numbers/__tests__/phone_numbers.spec.ts +774 -530
  237. package/src/talkpilot/phone_numbers/index.ts +2 -2
  238. package/src/talkpilot/phone_numbers/phone_numbers.getter.ts +324 -240
  239. package/src/talkpilot/phone_numbers/phone_numbers.schema.ts +17 -17
  240. package/src/talkpilot/phone_numbers/phone_numbers.types.ts +36 -30
  241. package/src/talkpilot/phone_numbers/phone_numbers.utils.ts +9 -9
  242. package/src/talkpilot/plans/__tests__/plans.spec.ts +70 -70
  243. package/src/talkpilot/plans/index.ts +2 -2
  244. package/src/talkpilot/plans/plans.getters.ts +132 -132
  245. package/src/talkpilot/plans/plans.types.ts +89 -89
  246. package/src/talkpilot/products/__tests__/products.getters.spec.ts +44 -44
  247. package/src/talkpilot/products/index.ts +2 -2
  248. package/src/talkpilot/products/products.getters.ts +12 -12
  249. package/src/talkpilot/products/products.types.ts +9 -9
  250. package/src/talkpilot/results/index.ts +7 -7
  251. package/src/talkpilot/results/results.getter.ts +39 -39
  252. package/src/talkpilot/results/results.schema.ts +25 -25
  253. package/src/talkpilot/results/results.types.ts +34 -34
  254. package/src/talkpilot/retry_analyze/__tests__/retryAnalyze.getters.spec.ts +156 -156
  255. package/src/talkpilot/retry_analyze/index.ts +2 -2
  256. package/src/talkpilot/retry_analyze/retryAnalyze.getters.ts +84 -84
  257. package/src/talkpilot/retry_analyze/retryAnalyze.types.ts +13 -13
  258. package/src/talkpilot/sessions/__tests__/sessions.spec.ts +147 -147
  259. package/src/talkpilot/sessions/index.ts +2 -2
  260. package/src/talkpilot/sessions/sessions.getter.ts +92 -92
  261. package/src/talkpilot/sessions/sessions.schema.ts +34 -34
  262. package/src/talkpilot/sessions/sessions.types.ts +30 -30
  263. package/src/talkpilot/subscriptions/__tests__/subscriptions.getters.utils.spec.ts +45 -45
  264. package/src/talkpilot/subscriptions/index.ts +3 -3
  265. package/src/talkpilot/subscriptions/subscriptions.getters.ts +146 -146
  266. package/src/talkpilot/subscriptions/subscriptions.getters.utils.ts +33 -33
  267. package/src/talkpilot/subscriptions/subscriptions.types.ts +66 -66
  268. package/src/talkpilot/utils/__tests__/query.utils.spec.ts +49 -49
  269. package/src/talkpilot/utils/query.utils.ts +21 -21
  270. package/src/test-utils/db-utils.ts +33 -33
  271. package/src/test-utils/factories/index.ts +20 -18
  272. package/src/test-utils/factories/municipal/cities.ts +16 -16
  273. package/src/test-utils/factories/municipal/departmentsSubjects.ts +37 -37
  274. package/src/test-utils/factories/municipal/muniIssues.ts +32 -32
  275. package/src/test-utils/factories/municipal/streets.ts +22 -22
  276. package/src/test-utils/factories/municipal/tickets.ts +39 -39
  277. package/src/test-utils/factories/talkpilot/agents.ts +19 -19
  278. package/src/test-utils/factories/talkpilot/calls.ts +37 -37
  279. package/src/test-utils/factories/talkpilot/clientAudioBuffers.ts +20 -20
  280. package/src/test-utils/factories/talkpilot/clients.ts +21 -0
  281. package/src/test-utils/factories/talkpilot/clientsConfig.ts +18 -18
  282. package/src/test-utils/factories/talkpilot/contextNotes.ts +40 -40
  283. package/src/test-utils/factories/talkpilot/flows.ts +33 -33
  284. package/src/test-utils/factories/talkpilot/groups.ts +33 -33
  285. package/src/test-utils/factories/talkpilot/phone_numbers.ts +22 -22
  286. package/src/test-utils/factories/talkpilot/results.ts +43 -0
  287. package/src/test-utils/factories/talkpilot/sessions.ts +35 -35
  288. package/src/test-utils/factories/websitalk/knowledgeDocuments.ts +29 -29
  289. package/src/test-utils/factories/websitalk/scanResources.ts +26 -26
  290. package/src/test-utils/factories/websitalk/scans.ts +30 -30
  291. package/src/test-utils/factories/websitalk/websiteUrls.ts +17 -17
  292. package/src/utils/date.utils.ts +126 -126
  293. package/src/utils/shared.types.ts +4 -4
  294. package/src/utils/validation.ts +23 -23
  295. package/src/websitalk/index.ts +18 -18
  296. package/src/websitalk/knowledgeDocuments/__tests__/knowledgeDocuments.spec.ts +238 -238
  297. package/src/websitalk/knowledgeDocuments/index.ts +3 -3
  298. package/src/websitalk/knowledgeDocuments/knowledgeDocuments.constants.ts +26 -26
  299. package/src/websitalk/knowledgeDocuments/knowledgeDocuments.getters.ts +95 -95
  300. package/src/websitalk/knowledgeDocuments/knowledgeDocuments.types.ts +75 -75
  301. package/src/websitalk/mongodb-client.ts +61 -61
  302. package/src/websitalk/scanResources/__tests__/scanResources.spec.ts +267 -267
  303. package/src/websitalk/scanResources/index.ts +4 -4
  304. package/src/websitalk/scanResources/scanResources.constants.ts +60 -60
  305. package/src/websitalk/scanResources/scanResources.getters.ts +128 -128
  306. package/src/websitalk/scanResources/scanResources.types.ts +105 -105
  307. package/src/websitalk/scanResources/scanResources.utils.ts +31 -31
  308. package/src/websitalk/scans/__tests__/scans.spec.ts +362 -362
  309. package/src/websitalk/scans/index.ts +4 -4
  310. package/src/websitalk/scans/scans.constants.ts +18 -18
  311. package/src/websitalk/scans/scans.getters.ts +172 -172
  312. package/src/websitalk/scans/scans.types.ts +58 -58
  313. package/src/websitalk/scans/scans.utils.ts +5 -5
  314. package/src/websitalk/websiteUrls/__tests__/websiteUrls.spec.ts +77 -77
  315. package/src/websitalk/websiteUrls/index.ts +2 -2
  316. package/src/websitalk/websiteUrls/websiteUrls.getters.ts +65 -65
  317. package/src/websitalk/websiteUrls/websiteUrls.types.ts +13 -13
  318. package/tsconfig.json +23 -23
  319. package/dist/talkpilot/subscriptions/subscriptions.utils.d.ts +0 -4
  320. package/dist/talkpilot/subscriptions/subscriptions.utils.d.ts.map +0 -1
  321. package/dist/talkpilot/subscriptions/subscriptions.utils.js +0 -20
  322. package/dist/talkpilot/subscriptions/subscriptions.utils.js.map +0 -1
@@ -0,0 +1,374 @@
1
+ import { ObjectId } from "mongodb";
2
+ import {
3
+ aggregateActiveCallsSummary,
4
+ aggregateTodayCallsSummary,
5
+ aggregateClientCallStats,
6
+ aggregateSessionCallStats,
7
+ getAllClientsLastCallDate,
8
+ findClientIdsByCallSids,
9
+ getCallsCollection,
10
+ } from "../calls.getters";
11
+ import { getSessionsCollection } from "../../sessions/sessions.getter";
12
+ import type { Call } from "../calls.types";
13
+ import {
14
+ createOutGoingCallDoc,
15
+ createIncomingCallDoc,
16
+ createSession,
17
+ } from "../../../test-utils/factories";
18
+
19
+ const insertCall = (call: Call) =>
20
+ getCallsCollection().insertOne({ ...call, env: call.env ?? "test" });
21
+
22
+ describe("calls.getters statistics", () => {
23
+ describe("aggregateActiveCallsSummary", () => {
24
+ it("should count distinct active calls within the last 2 hours, split incoming/outgoing", async () => {
25
+ const now = new Date();
26
+ await Promise.all([
27
+ insertCall(createIncomingCallDoc({ clientId: "clientA", status: "in-progress", updatedAt: now })),
28
+ insertCall(createOutGoingCallDoc({ clientId: "clientB", status: "in-progress", updatedAt: now })),
29
+ insertCall(createIncomingCallDoc({ clientId: "clientC", status: "completed", updatedAt: now })),
30
+ ]);
31
+
32
+ const summary = await aggregateActiveCallsSummary();
33
+
34
+ expect(summary.total).toBe(2);
35
+ expect(summary.incoming).toBe(1);
36
+ expect(summary.outgoing).toBe(1);
37
+ expect(summary.activeClientIds.sort()).toEqual(["clientA", "clientB"]);
38
+ });
39
+
40
+ it("should filter by clientId when provided", async () => {
41
+ const now = new Date();
42
+ await Promise.all([
43
+ insertCall(createOutGoingCallDoc({ clientId: "onlyThisClient", status: "in-progress", updatedAt: now })),
44
+ insertCall(createOutGoingCallDoc({ clientId: "otherClient", status: "in-progress", updatedAt: now })),
45
+ ]);
46
+
47
+ const summary = await aggregateActiveCallsSummary("onlyThisClient");
48
+ expect(summary.total).toBe(1);
49
+ expect(summary.activeClientIds).toEqual(["onlyThisClient"]);
50
+ });
51
+
52
+ it("should exclude calls whose updatedAt is older than 2 hours", async () => {
53
+ const threeHoursAgo = new Date(Date.now() - 3 * 60 * 60 * 1000);
54
+ await insertCall(createOutGoingCallDoc({ status: "in-progress", updatedAt: threeHoursAgo }));
55
+
56
+ const summary = await aggregateActiveCallsSummary();
57
+ expect(summary.total).toBe(0);
58
+ });
59
+ });
60
+
61
+ describe("aggregateTodayCallsSummary", () => {
62
+ it("should aggregate status/type counts and total minutes within the given date range", async () => {
63
+ const today = new Date().toISOString().slice(0, 10);
64
+ await Promise.all([
65
+ insertCall(createIncomingCallDoc({ status: "completed", callLength: 120, createdAt: new Date() })),
66
+ insertCall(createOutGoingCallDoc({ status: "failed", callLength: 30, createdAt: new Date() })),
67
+ ]);
68
+
69
+ const summary = await aggregateTodayCallsSummary({ dateFrom: today, dateTo: today });
70
+
71
+ expect(summary.total).toBe(2);
72
+ expect(summary.incoming).toBe(1);
73
+ expect(summary.outgoing).toBe(1);
74
+ expect(summary.completed).toBe(1);
75
+ expect(summary.failed).toBe(1);
76
+ expect(summary.totalMinutes).toBe(3); // ceil(150/60)
77
+ });
78
+
79
+ it("should respect the given timezone when resolving an explicit date", async () => {
80
+ // 23:30 UTC on 2026-01-01 is already 2026-01-02 in Asia/Jerusalem (+2).
81
+ const lateUtc = new Date("2026-01-01T23:30:00.000Z");
82
+ await insertCall(createOutGoingCallDoc({ status: "completed", createdAt: lateUtc }));
83
+
84
+ const summaryUtc = await aggregateTodayCallsSummary({
85
+ dateFrom: "2026-01-01",
86
+ dateTo: "2026-01-01",
87
+ timezone: "UTC",
88
+ });
89
+ expect(summaryUtc.total).toBe(1);
90
+
91
+ const summaryJerusalem = await aggregateTodayCallsSummary({
92
+ dateFrom: "2026-01-01",
93
+ dateTo: "2026-01-01",
94
+ timezone: "Asia/Jerusalem",
95
+ });
96
+ expect(summaryJerusalem.total).toBe(0);
97
+ });
98
+
99
+ it("should include a call's full history (not just today) when no date range is given", async () => {
100
+ const sixMonthsAgo = new Date(Date.now() - 180 * 24 * 60 * 60 * 1000);
101
+ await insertCall(createOutGoingCallDoc({ status: "completed", createdAt: sixMonthsAgo }));
102
+
103
+ const summary = await aggregateTodayCallsSummary({});
104
+ expect(summary.total).toBe(1);
105
+ });
106
+ });
107
+
108
+ describe("aggregateClientCallStats", () => {
109
+ it("should group call counts and minutes by clientId", async () => {
110
+ const today = new Date().toISOString().slice(0, 10);
111
+ await Promise.all([
112
+ insertCall(
113
+ createOutGoingCallDoc({ clientId: "clientX", status: "completed", callLength: 60, createdAt: new Date() }),
114
+ ),
115
+ insertCall(
116
+ createOutGoingCallDoc({ clientId: "clientX", status: "failed", callLength: 60, createdAt: new Date() }),
117
+ ),
118
+ ]);
119
+
120
+ const rows = await aggregateClientCallStats({ dateFrom: today, dateTo: today });
121
+ const row = rows.find((r) => r.clientId === "clientX");
122
+
123
+ expect(row?.totalCalls).toBe(2);
124
+ expect(row?.statusCounts).toMatchObject({ completed: 1, failed: 1 });
125
+ expect(row?.totalMinutes).toBe(2);
126
+ });
127
+
128
+ it("should not include other clients when filtered by clientId", async () => {
129
+ const today = new Date().toISOString().slice(0, 10);
130
+ await Promise.all([
131
+ insertCall(createOutGoingCallDoc({ clientId: "wantedClient", status: "completed", createdAt: new Date() })),
132
+ insertCall(createOutGoingCallDoc({ clientId: "unwantedClient", status: "completed", createdAt: new Date() })),
133
+ ]);
134
+
135
+ const rows = await aggregateClientCallStats({
136
+ dateFrom: today,
137
+ dateTo: today,
138
+ clientId: "wantedClient",
139
+ });
140
+
141
+ expect(rows).toHaveLength(1);
142
+ expect(rows[0].clientId).toBe("wantedClient");
143
+ });
144
+
145
+ it("should include a client's full history when no date range is given", async () => {
146
+ const sixMonthsAgo = new Date(Date.now() - 180 * 24 * 60 * 60 * 1000);
147
+ await Promise.all([
148
+ insertCall(createOutGoingCallDoc({ clientId: "longHistoryClient", status: "completed", createdAt: sixMonthsAgo })),
149
+ insertCall(createOutGoingCallDoc({ clientId: "longHistoryClient", status: "completed", createdAt: new Date() })),
150
+ ]);
151
+
152
+ const rows = await aggregateClientCallStats({});
153
+ const row = rows.find((r) => r.clientId === "longHistoryClient");
154
+
155
+ expect(row?.totalCalls).toBe(2);
156
+ });
157
+
158
+ it("should set lastCallDate to the most recent call", async () => {
159
+ const earlierCall = new Date("2026-01-01T00:00:00.000Z");
160
+ const laterCall = new Date("2026-03-10T00:00:00.000Z");
161
+ await Promise.all([
162
+ insertCall(createOutGoingCallDoc({ clientId: "lastCallDateClient", status: "completed", createdAt: earlierCall })),
163
+ insertCall(createOutGoingCallDoc({ clientId: "lastCallDateClient", status: "completed", createdAt: laterCall })),
164
+ ]);
165
+
166
+ const rows = await aggregateClientCallStats({});
167
+ const row = rows.find((r) => r.clientId === "lastCallDateClient");
168
+
169
+ expect(row?.lastCallDate).toEqual(laterCall);
170
+ });
171
+
172
+ it("should filter by clientId alone when no date range is given", async () => {
173
+ await Promise.all([
174
+ insertCall(createOutGoingCallDoc({ clientId: "onlyThisClientNoRange", status: "completed", createdAt: new Date() })),
175
+ insertCall(createOutGoingCallDoc({ clientId: "otherClientNoRange", status: "completed", createdAt: new Date() })),
176
+ ]);
177
+
178
+ const rows = await aggregateClientCallStats({ clientId: "onlyThisClientNoRange" });
179
+
180
+ expect(rows).toHaveLength(1);
181
+ expect(rows[0].clientId).toBe("onlyThisClientNoRange");
182
+ });
183
+
184
+ it("should count every real status separately, including queued; a missing status only inflates totalCalls", async () => {
185
+ const today = new Date().toISOString().slice(0, 10);
186
+ await Promise.all([
187
+ insertCall(createOutGoingCallDoc({ clientId: "statusBucketClient", status: "completed", createdAt: new Date() })),
188
+ insertCall(createOutGoingCallDoc({ clientId: "statusBucketClient", status: "canceled", createdAt: new Date() })),
189
+ insertCall(createOutGoingCallDoc({ clientId: "statusBucketClient", status: "queued" as any, createdAt: new Date() })),
190
+ insertCall(createOutGoingCallDoc({ clientId: "statusBucketClient", status: "ringing", createdAt: new Date() })),
191
+ insertCall(createOutGoingCallDoc({ clientId: "statusBucketClient", status: "initiated", createdAt: new Date() })),
192
+ insertCall(createOutGoingCallDoc({ clientId: "statusBucketClient", status: "answered", createdAt: new Date() })),
193
+ insertCall(createOutGoingCallDoc({ clientId: "statusBucketClient", status: undefined, createdAt: new Date() })),
194
+ ]);
195
+
196
+ const rows = await aggregateClientCallStats({ dateFrom: today, dateTo: today });
197
+ const row = rows.find((r) => r.clientId === "statusBucketClient");
198
+
199
+ expect(row?.totalCalls).toBe(7);
200
+ expect(row?.statusCounts).toMatchObject({
201
+ completed: 1,
202
+ canceled: 1,
203
+ queued: 1,
204
+ ringing: 1,
205
+ initiated: 1,
206
+ answered: 1,
207
+ });
208
+ });
209
+ });
210
+
211
+ describe("aggregateSessionCallStats", () => {
212
+ it("should group by sessionId and resolve the session's current name via the sessions collection", async () => {
213
+ const today = new Date().toISOString().slice(0, 10);
214
+ const sessionId = new ObjectId();
215
+ await getSessionsCollection().insertOne(createSession({ _id: sessionId, session_name: "My Session" }));
216
+ await insertCall(
217
+ createOutGoingCallDoc({ sessionId, status: "completed", createdAt: new Date() }),
218
+ );
219
+
220
+ const rows = await aggregateSessionCallStats({ dateFrom: today, dateTo: today });
221
+ const row = rows.find((r) => r.sessionId === sessionId.toString());
222
+
223
+ expect(row).toMatchObject({ sessionName: "My Session", totalCalls: 1 });
224
+ expect(row?.statusCounts).toMatchObject({ completed: 1 });
225
+ });
226
+
227
+ it("should always show the session's current name, even if it was renamed after some calls happened", async () => {
228
+ const today = new Date().toISOString().slice(0, 10);
229
+ const sessionId = new ObjectId();
230
+ const earlierCall = new Date(Date.now() - 60 * 60 * 1000);
231
+ const laterCall = new Date();
232
+
233
+ await getSessionsCollection().insertOne(createSession({ _id: sessionId, session_name: "New Name" }));
234
+ await Promise.all([
235
+ insertCall(createOutGoingCallDoc({ sessionId, status: "completed", createdAt: earlierCall })),
236
+ insertCall(createOutGoingCallDoc({ sessionId, status: "completed", createdAt: laterCall })),
237
+ ]);
238
+
239
+ const rows = await aggregateSessionCallStats({ dateFrom: today, dateTo: today });
240
+ const merged = rows.find((r) => r.sessionId === sessionId.toString());
241
+
242
+ expect(merged).toMatchObject({ sessionName: "New Name", totalCalls: 2 });
243
+ expect(merged?.statusCounts).toMatchObject({ completed: 2 });
244
+ });
245
+
246
+ it("should show 'Unknown' when the session no longer exists in the sessions collection", async () => {
247
+ const today = new Date().toISOString().slice(0, 10);
248
+ const orphanedSessionId = new ObjectId();
249
+ await insertCall(createOutGoingCallDoc({ sessionId: orphanedSessionId, status: "completed", createdAt: new Date() }));
250
+
251
+ const rows = await aggregateSessionCallStats({ dateFrom: today, dateTo: today });
252
+ const row = rows.find((r) => r.sessionId === orphanedSessionId.toString());
253
+
254
+ expect(row?.sessionName).toBe("Unknown");
255
+ });
256
+
257
+ it("should label a null sessionId as 'Incoming Call', not 'Unknown' — a call with no session is expected, not broken data", async () => {
258
+ const today = new Date().toISOString().slice(0, 10);
259
+ await Promise.all([
260
+ insertCall(createIncomingCallDoc({ status: "completed", createdAt: new Date() })),
261
+ insertCall(createIncomingCallDoc({ status: "failed", createdAt: new Date() })),
262
+ ]);
263
+
264
+ const rows = await aggregateSessionCallStats({ dateFrom: today, dateTo: today });
265
+ const row = rows.find((r) => r.sessionName === "Incoming Call");
266
+
267
+ expect(row).toBeDefined();
268
+ expect(row?.totalCalls).toBe(2);
269
+ expect(row?.statusCounts).toMatchObject({ completed: 1, failed: 1 });
270
+ expect(row?.sessionName).not.toBe("Unknown");
271
+ });
272
+
273
+ it("should only include the given client's sessions when clientId is provided", async () => {
274
+ const today = new Date().toISOString().slice(0, 10);
275
+ const sessionA = new ObjectId();
276
+ const sessionB = new ObjectId();
277
+ await getSessionsCollection().insertMany([
278
+ createSession({ _id: sessionA, session_name: "Session A" }),
279
+ createSession({ _id: sessionB, session_name: "Session B" }),
280
+ ]);
281
+ await Promise.all([
282
+ insertCall(createOutGoingCallDoc({ clientId: "clientA", sessionId: sessionA, status: "completed", createdAt: new Date() })),
283
+ insertCall(createOutGoingCallDoc({ clientId: "clientB", sessionId: sessionB, status: "completed", createdAt: new Date() })),
284
+ ]);
285
+
286
+ const rows = await aggregateSessionCallStats({
287
+ dateFrom: today,
288
+ dateTo: today,
289
+ clientId: "clientA",
290
+ });
291
+
292
+ expect(rows).toHaveLength(1);
293
+ expect(rows[0]).toMatchObject({ sessionId: sessionA.toString(), sessionName: "Session A" });
294
+ });
295
+
296
+ it("should exclude a session with no calls in the given date range", async () => {
297
+ const today = new Date().toISOString().slice(0, 10);
298
+ const longAgo = new Date(Date.now() - 30 * 24 * 60 * 60 * 1000);
299
+ const oldSessionId = new ObjectId();
300
+ await getSessionsCollection().insertOne(createSession({ _id: oldSessionId, session_name: "Old Session" }));
301
+ await insertCall(createOutGoingCallDoc({ sessionId: oldSessionId, status: "completed", createdAt: longAgo }));
302
+
303
+ const rows = await aggregateSessionCallStats({ dateFrom: today, dateTo: today });
304
+
305
+ expect(rows.find((r) => r.sessionId === oldSessionId.toString())).toBeUndefined();
306
+ });
307
+
308
+ it("should include a session's full history when no date range is given", async () => {
309
+ const longAgo = new Date(Date.now() - 30 * 24 * 60 * 60 * 1000);
310
+ const sessionId = new ObjectId();
311
+ await getSessionsCollection().insertOne(createSession({ _id: sessionId, session_name: "All Time Session" }));
312
+ await insertCall(createOutGoingCallDoc({ sessionId, status: "completed", createdAt: longAgo }));
313
+
314
+ const rows = await aggregateSessionCallStats({});
315
+ const row = rows.find((r) => r.sessionId === sessionId.toString());
316
+
317
+ expect(row?.totalCalls).toBe(1);
318
+ });
319
+
320
+ it("should count each real status separately, including queued", async () => {
321
+ const today = new Date().toISOString().slice(0, 10);
322
+ const sessionId = new ObjectId();
323
+ await getSessionsCollection().insertOne(createSession({ _id: sessionId, session_name: "Bucket Session" }));
324
+ await Promise.all([
325
+ insertCall(createOutGoingCallDoc({ sessionId, status: "completed", createdAt: new Date() })),
326
+ insertCall(createOutGoingCallDoc({ sessionId, status: "canceled", createdAt: new Date() })),
327
+ insertCall(createOutGoingCallDoc({ sessionId, status: "queued" as any, createdAt: new Date() })),
328
+ ]);
329
+
330
+ const rows = await aggregateSessionCallStats({ dateFrom: today, dateTo: today });
331
+ const row = rows.find((r) => r.sessionId === sessionId.toString());
332
+
333
+ expect(row?.totalCalls).toBe(3);
334
+ expect(row?.statusCounts).toMatchObject({ completed: 1, canceled: 1, queued: 1 });
335
+ });
336
+ });
337
+
338
+ describe("getAllClientsLastCallDate", () => {
339
+ it("should map each clientId to its most recent call, ignoring any date range", async () => {
340
+ const earlierCall = new Date("2026-01-01T00:00:00.000Z");
341
+ const laterCall = new Date("2026-03-10T00:00:00.000Z");
342
+ await Promise.all([
343
+ insertCall(createOutGoingCallDoc({ clientId: "lastCallMapClientA", status: "completed", createdAt: earlierCall })),
344
+ insertCall(createOutGoingCallDoc({ clientId: "lastCallMapClientA", status: "completed", createdAt: laterCall })),
345
+ insertCall(createOutGoingCallDoc({ clientId: "lastCallMapClientB", status: "completed", createdAt: earlierCall })),
346
+ ]);
347
+
348
+ const map = await getAllClientsLastCallDate();
349
+
350
+ expect(map.get("lastCallMapClientA")).toEqual(laterCall);
351
+ expect(map.get("lastCallMapClientB")).toEqual(earlierCall);
352
+ });
353
+ });
354
+
355
+ describe("findClientIdsByCallSids", () => {
356
+ it("should map each callSid to the clientId that owns it", async () => {
357
+ await Promise.all([
358
+ insertCall(createOutGoingCallDoc({ clientId: "clientA", callSid: "CAaaa" })),
359
+ insertCall(createOutGoingCallDoc({ clientId: "clientB", callSid: "CAbbb" })),
360
+ ]);
361
+
362
+ const map = await findClientIdsByCallSids(["CAaaa", "CAbbb", "CAunknown"]);
363
+
364
+ expect(map.get("CAaaa")).toBe("clientA");
365
+ expect(map.get("CAbbb")).toBe("clientB");
366
+ expect(map.has("CAunknown")).toBe(false);
367
+ });
368
+
369
+ it("should return an empty map when given no callSids", async () => {
370
+ const map = await findClientIdsByCallSids([]);
371
+ expect(map.size).toBe(0);
372
+ });
373
+ });
374
+ });