@tstdl/base 0.93.181 → 0.93.183

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 (353) hide show
  1. package/api/server/api-request-token.provider.js +1 -1
  2. package/api/server/gateway.js +8 -3
  3. package/authentication/authentication.api.d.ts +13 -40
  4. package/authentication/authentication.api.js +5 -14
  5. package/authentication/client/authentication.service.d.ts +6 -14
  6. package/authentication/client/authentication.service.js +22 -4
  7. package/authentication/client/module.d.ts +1 -1
  8. package/authentication/client/module.js +4 -4
  9. package/authentication/models/index.d.ts +1 -0
  10. package/authentication/models/index.js +1 -0
  11. package/authentication/models/totp-results.model.d.ts +11 -0
  12. package/authentication/models/totp-results.model.js +37 -0
  13. package/authentication/server/authentication.api-controller.d.ts +3 -3
  14. package/authentication/server/authentication.api-controller.js +31 -4
  15. package/authentication/server/authentication.service.d.ts +5 -14
  16. package/authentication/server/authentication.service.js +6 -4
  17. package/core.d.ts +0 -5
  18. package/core.js +0 -8
  19. package/document-management/api/document-management.api.d.ts +2 -2
  20. package/document-management/service-models/document.service-model.d.ts +1 -1
  21. package/examples/config.d.ts +25 -0
  22. package/examples/config.js +26 -0
  23. package/notification/server/module.d.ts +1 -1
  24. package/notification/server/module.js +1 -1
  25. package/package.json +5 -5
  26. package/signals/api.d.ts +5 -1
  27. package/signals/api.js +3 -1
  28. package/signals/implementation/api.d.ts +13 -5
  29. package/signals/implementation/api.js +7 -1
  30. package/signals/implementation/asserts.d.ts +2 -2
  31. package/signals/implementation/asserts.js +3 -3
  32. package/signals/implementation/computed.d.ts +7 -34
  33. package/signals/implementation/computed.js +14 -83
  34. package/signals/implementation/configure.js +6 -2
  35. package/signals/implementation/effect.d.ts +65 -46
  36. package/signals/implementation/effect.js +97 -62
  37. package/signals/implementation/index.d.ts +2 -4
  38. package/signals/implementation/index.js +2 -4
  39. package/signals/implementation/linked_signal.d.ts +36 -0
  40. package/signals/implementation/linked_signal.js +34 -0
  41. package/signals/implementation/primitive/computed.d.ts +55 -0
  42. package/signals/implementation/primitive/computed.js +107 -0
  43. package/signals/implementation/primitive/effect.d.ts +26 -0
  44. package/signals/implementation/primitive/effect.js +31 -0
  45. package/signals/implementation/{equality.d.ts → primitive/equality.d.ts} +1 -1
  46. package/signals/implementation/{equality.js → primitive/equality.js} +1 -1
  47. package/signals/implementation/primitive/errors.d.ts +10 -0
  48. package/signals/implementation/{errors.js → primitive/errors.js} +3 -4
  49. package/signals/implementation/primitive/formatter.d.ts +19 -0
  50. package/signals/implementation/primitive/formatter.js +136 -0
  51. package/signals/implementation/{graph.d.ts → primitive/graph.d.ts} +68 -36
  52. package/signals/implementation/primitive/graph.js +386 -0
  53. package/signals/implementation/primitive/linked_signal.d.ts +46 -0
  54. package/signals/implementation/primitive/linked_signal.js +110 -0
  55. package/signals/implementation/primitive/signal.d.ts +31 -0
  56. package/signals/implementation/primitive/signal.js +80 -0
  57. package/signals/implementation/primitive/untracked.d.ts +12 -0
  58. package/signals/implementation/primitive/untracked.js +23 -0
  59. package/signals/implementation/{watch.d.ts → primitive/watch.d.ts} +1 -2
  60. package/signals/implementation/{watch.js → primitive/watch.js} +22 -16
  61. package/signals/implementation/resource/api.d.ts +275 -0
  62. package/signals/implementation/resource/api.js +26 -0
  63. package/signals/implementation/resource/debounce.d.ts +13 -0
  64. package/signals/implementation/resource/debounce.js +113 -0
  65. package/signals/implementation/resource/from_snapshots.d.ts +16 -0
  66. package/signals/implementation/resource/from_snapshots.js +44 -0
  67. package/signals/implementation/resource/index.d.ts +11 -0
  68. package/signals/implementation/resource/index.js +11 -0
  69. package/signals/implementation/resource/resource.d.ts +110 -0
  70. package/signals/implementation/resource/resource.js +402 -0
  71. package/signals/implementation/root_effect_scheduler.d.ts +50 -0
  72. package/signals/implementation/root_effect_scheduler.js +66 -0
  73. package/signals/implementation/signal.d.ts +42 -18
  74. package/signals/implementation/signal.js +29 -49
  75. package/signals/implementation/to-observable.d.ts +12 -5
  76. package/signals/implementation/to-observable.js +12 -2
  77. package/signals/implementation/to-signal.d.ts +9 -18
  78. package/signals/implementation/to-signal.js +46 -13
  79. package/signals/implementation/untracked.d.ts +1 -1
  80. package/signals/implementation/untracked.js +3 -11
  81. package/signals/operators/debounce.d.ts +8 -0
  82. package/signals/operators/debounce.js +19 -0
  83. package/signals/operators/derive-async.js +43 -15
  84. package/signals/operators/index.d.ts +2 -0
  85. package/signals/operators/index.js +2 -0
  86. package/signals/operators/throttle.d.ts +8 -0
  87. package/signals/operators/throttle.js +31 -0
  88. package/ai/genkit/tests/multi-region.test.d.ts +0 -2
  89. package/ai/genkit/tests/multi-region.test.js +0 -179
  90. package/ai/genkit/tests/token-limit-fallback.test.d.ts +0 -2
  91. package/ai/genkit/tests/token-limit-fallback.test.js +0 -209
  92. package/ai/prompts/tests/prompt-builder.test.d.ts +0 -1
  93. package/ai/prompts/tests/prompt-builder.test.js +0 -22
  94. package/ai/tests/instructions-formatter.test.d.ts +0 -1
  95. package/ai/tests/instructions-formatter.test.js +0 -116
  96. package/ai/tests/steering.test.d.ts +0 -1
  97. package/ai/tests/steering.test.js +0 -37
  98. package/api/client/tests/api-client.test.d.ts +0 -1
  99. package/api/client/tests/api-client.test.js +0 -194
  100. package/api/server/tests/csrf.middleware.test.d.ts +0 -1
  101. package/api/server/tests/csrf.middleware.test.js +0 -91
  102. package/authentication/tests/authentication-password-requirements.validator.test.d.ts +0 -1
  103. package/authentication/tests/authentication-password-requirements.validator.test.js +0 -29
  104. package/authentication/tests/authentication.api-controller.test.d.ts +0 -1
  105. package/authentication/tests/authentication.api-controller.test.js +0 -156
  106. package/authentication/tests/authentication.api-request-token.provider.test.d.ts +0 -1
  107. package/authentication/tests/authentication.api-request-token.provider.test.js +0 -48
  108. package/authentication/tests/authentication.client-error-handling.test.d.ts +0 -1
  109. package/authentication/tests/authentication.client-error-handling.test.js +0 -123
  110. package/authentication/tests/authentication.client-middleware.test.d.ts +0 -1
  111. package/authentication/tests/authentication.client-middleware.test.js +0 -118
  112. package/authentication/tests/authentication.client-service-methods.test.d.ts +0 -1
  113. package/authentication/tests/authentication.client-service-methods.test.js +0 -177
  114. package/authentication/tests/authentication.client-service-refresh.test.d.ts +0 -1
  115. package/authentication/tests/authentication.client-service-refresh.test.js +0 -153
  116. package/authentication/tests/authentication.client-service.test.d.ts +0 -1
  117. package/authentication/tests/authentication.client-service.test.js +0 -76
  118. package/authentication/tests/authentication.refresh-busy-loop.test.d.ts +0 -1
  119. package/authentication/tests/authentication.refresh-busy-loop.test.js +0 -84
  120. package/authentication/tests/authentication.service.test.d.ts +0 -1
  121. package/authentication/tests/authentication.service.test.js +0 -167
  122. package/authentication/tests/authentication.test-ancillary-service.d.ts +0 -9
  123. package/authentication/tests/authentication.test-ancillary-service.js +0 -27
  124. package/authentication/tests/brute-force-protection.test.d.ts +0 -1
  125. package/authentication/tests/brute-force-protection.test.js +0 -211
  126. package/authentication/tests/helper.test.d.ts +0 -1
  127. package/authentication/tests/helper.test.js +0 -122
  128. package/authentication/tests/password-requirements.error.test.d.ts +0 -1
  129. package/authentication/tests/password-requirements.error.test.js +0 -14
  130. package/authentication/tests/remember.api.test.d.ts +0 -1
  131. package/authentication/tests/remember.api.test.js +0 -117
  132. package/authentication/tests/remember.service.test.d.ts +0 -1
  133. package/authentication/tests/remember.service.test.js +0 -83
  134. package/authentication/tests/subject.service.test.d.ts +0 -1
  135. package/authentication/tests/subject.service.test.js +0 -140
  136. package/authentication/tests/suspended-subject.test.d.ts +0 -1
  137. package/authentication/tests/suspended-subject.test.js +0 -120
  138. package/authentication/tests/totp.enrollment.test.d.ts +0 -1
  139. package/authentication/tests/totp.enrollment.test.js +0 -123
  140. package/authentication/tests/totp.login.test.d.ts +0 -1
  141. package/authentication/tests/totp.login.test.js +0 -213
  142. package/authentication/tests/totp.recovery-codes.test.d.ts +0 -1
  143. package/authentication/tests/totp.recovery-codes.test.js +0 -97
  144. package/authentication/tests/totp.status.test.d.ts +0 -1
  145. package/authentication/tests/totp.status.test.js +0 -72
  146. package/cancellation/tests/coverage.test.d.ts +0 -1
  147. package/cancellation/tests/coverage.test.js +0 -49
  148. package/cancellation/tests/leak.test.d.ts +0 -1
  149. package/cancellation/tests/leak.test.js +0 -35
  150. package/cancellation/tests/token.test.d.ts +0 -1
  151. package/cancellation/tests/token.test.js +0 -136
  152. package/circuit-breaker/tests/circuit-breaker.test.d.ts +0 -1
  153. package/circuit-breaker/tests/circuit-breaker.test.js +0 -116
  154. package/cryptography/tests/cryptography.test.d.ts +0 -1
  155. package/cryptography/tests/cryptography.test.js +0 -175
  156. package/cryptography/tests/jwt.test.d.ts +0 -1
  157. package/cryptography/tests/jwt.test.js +0 -54
  158. package/cryptography/tests/modern.test.d.ts +0 -1
  159. package/cryptography/tests/modern.test.js +0 -105
  160. package/cryptography/tests/module.test.d.ts +0 -1
  161. package/cryptography/tests/module.test.js +0 -100
  162. package/cryptography/tests/totp.test.d.ts +0 -1
  163. package/cryptography/tests/totp.test.js +0 -108
  164. package/document-management/tests/ai-config-hierarchy.test.d.ts +0 -1
  165. package/document-management/tests/ai-config-hierarchy.test.js +0 -59
  166. package/document-management/tests/ai-config-integration.test.d.ts +0 -1
  167. package/document-management/tests/ai-config-integration.test.js +0 -125
  168. package/document-management/tests/ai-config-merge.test.d.ts +0 -1
  169. package/document-management/tests/ai-config-merge.test.js +0 -46
  170. package/document-management/tests/document-management-ai-overrides.test.d.ts +0 -1
  171. package/document-management/tests/document-management-ai-overrides.test.js +0 -63
  172. package/document-management/tests/document-management-core.test.d.ts +0 -1
  173. package/document-management/tests/document-management-core.test.js +0 -157
  174. package/document-management/tests/document-management.api.test.d.ts +0 -1
  175. package/document-management/tests/document-management.api.test.js +0 -101
  176. package/document-management/tests/document-statistics.service.test.d.ts +0 -1
  177. package/document-management/tests/document-statistics.service.test.js +0 -498
  178. package/document-management/tests/document-validation-ai-overrides.test.d.ts +0 -1
  179. package/document-management/tests/document-validation-ai-overrides.test.js +0 -87
  180. package/document-management/tests/document.service.test.d.ts +0 -1
  181. package/document-management/tests/document.service.test.js +0 -143
  182. package/document-management/tests/enum-helpers.test.d.ts +0 -1
  183. package/document-management/tests/enum-helpers.test.js +0 -452
  184. package/document-management/tests/helper.d.ts +0 -24
  185. package/document-management/tests/helper.js +0 -39
  186. package/errors/tests/format.test.d.ts +0 -1
  187. package/errors/tests/format.test.js +0 -84
  188. package/http/tests/server-timing.test.d.ts +0 -1
  189. package/http/tests/server-timing.test.js +0 -42
  190. package/injector/tests/advanced.test.d.ts +0 -1
  191. package/injector/tests/advanced.test.js +0 -116
  192. package/injector/tests/async-init.test.d.ts +0 -1
  193. package/injector/tests/async-init.test.js +0 -77
  194. package/injector/tests/basic.test.d.ts +0 -1
  195. package/injector/tests/basic.test.js +0 -114
  196. package/injector/tests/hierarchical.test.d.ts +0 -1
  197. package/injector/tests/hierarchical.test.js +0 -59
  198. package/injector/tests/leak.test.d.ts +0 -1
  199. package/injector/tests/leak.test.js +0 -45
  200. package/injector/tests/lifecycles.test.d.ts +0 -1
  201. package/injector/tests/lifecycles.test.js +0 -109
  202. package/logger/tests/pretty-print.test.d.ts +0 -1
  203. package/logger/tests/pretty-print.test.js +0 -60
  204. package/notification/tests/notification-api.test.d.ts +0 -1
  205. package/notification/tests/notification-api.test.js +0 -124
  206. package/notification/tests/notification-client.test.d.ts +0 -1
  207. package/notification/tests/notification-client.test.js +0 -101
  208. package/notification/tests/notification-flow.test.d.ts +0 -1
  209. package/notification/tests/notification-flow.test.js +0 -296
  210. package/notification/tests/notification-sse.service.test.d.ts +0 -1
  211. package/notification/tests/notification-sse.service.test.js +0 -43
  212. package/notification/tests/notification-type.service.test.d.ts +0 -1
  213. package/notification/tests/notification-type.service.test.js +0 -41
  214. package/object-storage/s3/tests/s3.object-storage.integration.test.d.ts +0 -1
  215. package/object-storage/s3/tests/s3.object-storage.integration.test.js +0 -303
  216. package/orm/tests/build-jsonb.test.d.ts +0 -1
  217. package/orm/tests/build-jsonb.test.js +0 -39
  218. package/orm/tests/data-types.test.d.ts +0 -1
  219. package/orm/tests/data-types.test.js +0 -39
  220. package/orm/tests/database-extension.test.d.ts +0 -1
  221. package/orm/tests/database-extension.test.js +0 -63
  222. package/orm/tests/database-migration.test.d.ts +0 -1
  223. package/orm/tests/database-migration.test.js +0 -83
  224. package/orm/tests/decorators.test.d.ts +0 -1
  225. package/orm/tests/decorators.test.js +0 -77
  226. package/orm/tests/encryption.test.d.ts +0 -1
  227. package/orm/tests/encryption.test.js +0 -31
  228. package/orm/tests/query-complex.test.d.ts +0 -1
  229. package/orm/tests/query-complex.test.js +0 -172
  230. package/orm/tests/query-converter-complex.test.d.ts +0 -1
  231. package/orm/tests/query-converter-complex.test.js +0 -131
  232. package/orm/tests/query-converter.test.d.ts +0 -1
  233. package/orm/tests/query-converter.test.js +0 -123
  234. package/orm/tests/repository-advanced.test.d.ts +0 -1
  235. package/orm/tests/repository-advanced.test.js +0 -189
  236. package/orm/tests/repository-attributes.test.d.ts +0 -1
  237. package/orm/tests/repository-attributes.test.js +0 -83
  238. package/orm/tests/repository-compound-primary-key.test.d.ts +0 -2
  239. package/orm/tests/repository-compound-primary-key.test.js +0 -226
  240. package/orm/tests/repository-comprehensive.test.d.ts +0 -1
  241. package/orm/tests/repository-comprehensive.test.js +0 -162
  242. package/orm/tests/repository-coverage.test.d.ts +0 -2
  243. package/orm/tests/repository-coverage.test.js +0 -242
  244. package/orm/tests/repository-cti-complex.test.d.ts +0 -1
  245. package/orm/tests/repository-cti-complex.test.js +0 -151
  246. package/orm/tests/repository-cti-embedded.test.d.ts +0 -1
  247. package/orm/tests/repository-cti-embedded.test.js +0 -178
  248. package/orm/tests/repository-cti-extensive.test.d.ts +0 -2
  249. package/orm/tests/repository-cti-extensive.test.js +0 -279
  250. package/orm/tests/repository-cti-mapping.test.d.ts +0 -2
  251. package/orm/tests/repository-cti-mapping.test.js +0 -108
  252. package/orm/tests/repository-cti-search.test.d.ts +0 -1
  253. package/orm/tests/repository-cti-search.test.js +0 -141
  254. package/orm/tests/repository-cti-soft-delete.test.d.ts +0 -2
  255. package/orm/tests/repository-cti-soft-delete.test.js +0 -103
  256. package/orm/tests/repository-cti-transactions.test.d.ts +0 -1
  257. package/orm/tests/repository-cti-transactions.test.js +0 -112
  258. package/orm/tests/repository-cti-upsert-many.test.d.ts +0 -2
  259. package/orm/tests/repository-cti-upsert-many.test.js +0 -115
  260. package/orm/tests/repository-cti.test.d.ts +0 -2
  261. package/orm/tests/repository-cti.test.js +0 -390
  262. package/orm/tests/repository-edge-cases.test.d.ts +0 -1
  263. package/orm/tests/repository-edge-cases.test.js +0 -178
  264. package/orm/tests/repository-expiration.test.d.ts +0 -2
  265. package/orm/tests/repository-expiration.test.js +0 -140
  266. package/orm/tests/repository-extra-coverage.test.d.ts +0 -2
  267. package/orm/tests/repository-extra-coverage.test.js +0 -402
  268. package/orm/tests/repository-mapping.test.d.ts +0 -2
  269. package/orm/tests/repository-mapping.test.js +0 -65
  270. package/orm/tests/repository-regression.test.d.ts +0 -1
  271. package/orm/tests/repository-regression.test.js +0 -288
  272. package/orm/tests/repository-search-coverage.test.d.ts +0 -1
  273. package/orm/tests/repository-search-coverage.test.js +0 -107
  274. package/orm/tests/repository-search.test.d.ts +0 -1
  275. package/orm/tests/repository-search.test.js +0 -105
  276. package/orm/tests/repository-soft-delete.test.d.ts +0 -1
  277. package/orm/tests/repository-soft-delete.test.js +0 -118
  278. package/orm/tests/repository-transactions-nested.test.d.ts +0 -1
  279. package/orm/tests/repository-transactions-nested.test.js +0 -178
  280. package/orm/tests/repository-types.test.d.ts +0 -1
  281. package/orm/tests/repository-types.test.js +0 -184
  282. package/orm/tests/repository-undelete.test.d.ts +0 -2
  283. package/orm/tests/repository-undelete.test.js +0 -201
  284. package/orm/tests/schema-converter.test.d.ts +0 -1
  285. package/orm/tests/schema-converter.test.js +0 -82
  286. package/orm/tests/schema-generation.test.d.ts +0 -2
  287. package/orm/tests/schema-generation.test.js +0 -174
  288. package/orm/tests/sql-helpers.test.d.ts +0 -1
  289. package/orm/tests/sql-helpers.test.js +0 -67
  290. package/orm/tests/transaction-safety.test.d.ts +0 -1
  291. package/orm/tests/transaction-safety.test.js +0 -81
  292. package/orm/tests/transactional.test.d.ts +0 -1
  293. package/orm/tests/transactional.test.js +0 -215
  294. package/orm/tests/utils.test.d.ts +0 -1
  295. package/orm/tests/utils.test.js +0 -70
  296. package/pdf/tests/utils.test.d.ts +0 -1
  297. package/pdf/tests/utils.test.js +0 -187
  298. package/process/tests/spawn.test.d.ts +0 -1
  299. package/process/tests/spawn.test.js +0 -182
  300. package/rate-limit/tests/postgres-rate-limiter.test.d.ts +0 -1
  301. package/rate-limit/tests/postgres-rate-limiter.test.js +0 -84
  302. package/renderer/tests/renderer.test.d.ts +0 -1
  303. package/renderer/tests/renderer.test.js +0 -88
  304. package/rpc/tests/rpc.integration.test.d.ts +0 -1
  305. package/rpc/tests/rpc.integration.test.js +0 -615
  306. package/signals/implementation/errors.d.ts +0 -2
  307. package/signals/implementation/graph.js +0 -312
  308. package/signals/implementation/writable-signal.d.ts +0 -48
  309. package/signals/implementation/writable-signal.js +0 -32
  310. package/task-queue/tests/coverage-branch.test.d.ts +0 -1
  311. package/task-queue/tests/coverage-branch.test.js +0 -395
  312. package/task-queue/tests/coverage-enhancement.test.d.ts +0 -1
  313. package/task-queue/tests/coverage-enhancement.test.js +0 -150
  314. package/task-queue/tests/dag.test.d.ts +0 -1
  315. package/task-queue/tests/dag.test.js +0 -188
  316. package/task-queue/tests/dependencies.test.d.ts +0 -1
  317. package/task-queue/tests/dependencies.test.js +0 -296
  318. package/task-queue/tests/enqueue-batch.test.d.ts +0 -1
  319. package/task-queue/tests/enqueue-batch.test.js +0 -125
  320. package/task-queue/tests/enqueue-item.test.d.ts +0 -1
  321. package/task-queue/tests/enqueue-item.test.js +0 -12
  322. package/task-queue/tests/fan-out-spawning.test.d.ts +0 -1
  323. package/task-queue/tests/fan-out-spawning.test.js +0 -94
  324. package/task-queue/tests/idempotent-replacement.test.d.ts +0 -1
  325. package/task-queue/tests/idempotent-replacement.test.js +0 -114
  326. package/task-queue/tests/missing-idempotent-tasks.test.d.ts +0 -1
  327. package/task-queue/tests/missing-idempotent-tasks.test.js +0 -39
  328. package/task-queue/tests/optimization-edge-cases.test.d.ts +0 -1
  329. package/task-queue/tests/optimization-edge-cases.test.js +0 -124
  330. package/task-queue/tests/queue-generic.test.d.ts +0 -1
  331. package/task-queue/tests/queue-generic.test.js +0 -8
  332. package/task-queue/tests/queue.test.d.ts +0 -1
  333. package/task-queue/tests/queue.test.js +0 -756
  334. package/task-queue/tests/shutdown.test.d.ts +0 -1
  335. package/task-queue/tests/shutdown.test.js +0 -41
  336. package/task-queue/tests/task-context.test.d.ts +0 -1
  337. package/task-queue/tests/task-context.test.js +0 -7
  338. package/task-queue/tests/task-union.test.d.ts +0 -1
  339. package/task-queue/tests/task-union.test.js +0 -18
  340. package/task-queue/tests/transactions.test.d.ts +0 -1
  341. package/task-queue/tests/transactions.test.js +0 -47
  342. package/task-queue/tests/typing.test.d.ts +0 -1
  343. package/task-queue/tests/typing.test.js +0 -9
  344. package/task-queue/tests/worker.test.d.ts +0 -1
  345. package/task-queue/tests/worker.test.js +0 -258
  346. package/task-queue/tests/zombie-parent.test.d.ts +0 -1
  347. package/task-queue/tests/zombie-parent.test.js +0 -45
  348. package/task-queue/tests/zombie-recovery.test.d.ts +0 -1
  349. package/task-queue/tests/zombie-recovery.test.js +0 -51
  350. package/utils/tests/backoff.test.d.ts +0 -1
  351. package/utils/tests/backoff.test.js +0 -41
  352. package/utils/tests/retry-with-backoff.test.d.ts +0 -1
  353. package/utils/tests/retry-with-backoff.test.js +0 -49
@@ -1,101 +0,0 @@
1
- import { afterAll, beforeAll, beforeEach, describe, expect, test, vi } from 'vitest';
2
- import { GenkitModuleOptions } from '../../ai/genkit/module.js';
3
- import { runInInjectionContext } from '../../injector/index.js';
4
- import { ObjectStorage } from '../../object-storage/index.js';
5
- import { TaskQueue } from '../../task-queue/index.js';
6
- import { clearTenantData, setupIntegrationTest } from '../../testing/index.js';
7
- import { DocumentManagementAuthorizationService } from '../authorization/document-management-authorization.service.js';
8
- import { DocumentManagementApiController } from '../server/api/document-management.api.js';
9
- import { configureDocumentManagement } from '../server/configure.js';
10
- import { DocumentCollectionService } from '../server/services/document-collection.service.js';
11
- import { DocumentManagementAiService } from '../server/services/document-management-ai.service.js';
12
- import { DocumentService } from '../server/services/document.service.js';
13
- import { TestDocumentManagementAncillaryService, TestDocumentManagementAuthorizationService } from './helper.js';
14
- describe('DocumentManagementApi Stats', () => {
15
- let injector;
16
- let database;
17
- let controller;
18
- let documentService;
19
- let collectionService;
20
- const schema = 'document_management';
21
- const tenantId = crypto.randomUUID();
22
- beforeAll(async () => {
23
- ({ injector, database } = await setupIntegrationTest({
24
- modules: { taskQueue: false, messageBus: true, documentManagement: true },
25
- orm: { schema },
26
- }));
27
- injector.register(GenkitModuleOptions, { useValue: {} });
28
- injector.register(DocumentManagementAiService, { useValue: { extractContent: vi.fn(), classifyDocumentType: vi.fn(), extractData: vi.fn(), findSuitableCollectionsForDocument: vi.fn(), findSuitableRequestForDocument: vi.fn() } });
29
- injector.register(ObjectStorage, {
30
- useValue: {
31
- uploadObject: vi.fn(),
32
- getDownloadUrl: vi.fn(),
33
- getContent: vi.fn(),
34
- getContentStream: vi.fn(),
35
- getObject: vi.fn(),
36
- exists: vi.fn(),
37
- },
38
- });
39
- injector.register(TaskQueue, {
40
- useValue: {
41
- enqueue: vi.fn(),
42
- enqueueMany: vi.fn(),
43
- process: vi.fn(),
44
- },
45
- });
46
- configureDocumentManagement({
47
- ancillaryService: TestDocumentManagementAncillaryService,
48
- authorizationService: TestDocumentManagementAuthorizationService,
49
- fileObjectStorageModule: 'documents',
50
- fileUploadObjectStorageModule: 'document-uploads',
51
- filePreviewObjectStorageModule: 'document-previews',
52
- injector,
53
- });
54
- controller = await injector.resolveAsync(DocumentManagementApiController);
55
- documentService = await injector.resolveAsync(DocumentService);
56
- collectionService = await injector.resolveAsync(DocumentCollectionService);
57
- });
58
- afterAll(async () => {
59
- await injector?.dispose();
60
- });
61
- beforeEach(async () => {
62
- await clearTenantData(database, schema, ['collection_assignment', 'workflow', 'document', 'collection', 'tag', 'type', 'category'], tenantId);
63
- });
64
- test('getStatistics API endpoint', async () => {
65
- await runInInjectionContext(injector, async () => {
66
- const collection = await collectionService.createCollection(tenantId, null);
67
- const authService = injector.resolve(DocumentManagementAuthorizationService);
68
- vi.spyOn(authService, 'getTenantId').mockResolvedValue(tenantId);
69
- await documentService.create(tenantId, {
70
- assignment: { collections: [collection.id] },
71
- skipWorkflow: true,
72
- }, new Uint8Array([1, 2, 3]));
73
- const mockContext = {
74
- getToken: async () => ({ payload: { tenantId } }),
75
- parameters: {
76
- includeTotalCount: true,
77
- includeStorageUsage: true,
78
- collectionIds: [collection.id],
79
- },
80
- };
81
- const stats = await controller.getStatistics(mockContext);
82
- expect(stats.totalCount).toBe(1);
83
- expect(stats.storageUsage).toBe(3);
84
- });
85
- });
86
- test('getStatistics API endpoint should deny access if collection is restricted', async () => {
87
- await runInInjectionContext(injector, async () => {
88
- const authService = injector.resolve(DocumentManagementAuthorizationService);
89
- vi.spyOn(authService, 'getTenantId').mockResolvedValue(tenantId);
90
- vi.spyOn(authService, 'canReadCollection').mockResolvedValue(false);
91
- const mockContext = {
92
- getToken: async () => ({ payload: { tenantId } }),
93
- parameters: {
94
- includeTotalCount: true,
95
- collectionIds: ['some-collection-id'],
96
- },
97
- };
98
- await expect(controller.getStatistics(mockContext)).rejects.toThrow('You are not allowed to read collection some-collection-id');
99
- });
100
- });
101
- });
@@ -1,498 +0,0 @@
1
- import { afterAll, beforeAll, beforeEach, describe, expect, test, vi } from 'vitest';
2
- import { GenkitModuleOptions } from '../../ai/genkit/module.js';
3
- import { runInInjectionContext } from '../../injector/index.js';
4
- import { ObjectStorage } from '../../object-storage/index.js';
5
- import { getRepository } from '../../orm/server/index.js';
6
- import { clearTenantData, setupIntegrationTest } from '../../testing/index.js';
7
- import { DocumentValidationDefinition } from '../models/document-validation-definition.model.js';
8
- import { DocumentValidationExecution, DocumentValidationExecutionState, DocumentValidationResultStatus } from '../models/document-validation-execution.model.js';
9
- import { DocumentWorkflow, DocumentWorkflowState, DocumentWorkflowStep } from '../models/document-workflow.model.js';
10
- import { DocumentApproval } from '../models/document.model.js';
11
- import { configureDocumentManagement } from '../server/configure.js';
12
- import { DocumentCategoryTypeService } from '../server/services/document-category-type.service.js';
13
- import { DocumentCollectionService } from '../server/services/document-collection.service.js';
14
- import { DocumentManagementAiService } from '../server/services/document-management-ai.service.js';
15
- import { DocumentStatisticsService } from '../server/services/document-statistics.service.js';
16
- import { DocumentTagService } from '../server/services/document-tag.service.js';
17
- import { DocumentService } from '../server/services/document.service.js';
18
- import { TestDocumentManagementAncillaryService, TestDocumentManagementAuthorizationService } from './helper.js';
19
- describe('DocumentStatisticsService', () => {
20
- let injector;
21
- let database;
22
- let documentService;
23
- let statsService;
24
- let collectionService;
25
- let tagService;
26
- let categoryTypeService;
27
- const schema = 'document_management';
28
- const tenantId = crypto.randomUUID();
29
- beforeAll(async () => {
30
- ({ injector, database } = await setupIntegrationTest({
31
- modules: { taskQueue: true, documentManagement: true },
32
- orm: { schema },
33
- }));
34
- const mockObjectStorage = {
35
- uploadObject: vi.fn(),
36
- getDownloadUrl: vi.fn(),
37
- getContent: vi.fn(),
38
- getContentStream: vi.fn(),
39
- getObject: vi.fn(),
40
- exists: vi.fn(),
41
- };
42
- const mockAiService = {
43
- extractContent: vi.fn(),
44
- classifyDocumentType: vi.fn(),
45
- extractData: vi.fn(),
46
- findSuitableCollectionsForDocument: vi.fn(),
47
- findSuitableRequestForDocument: vi.fn(),
48
- };
49
- injector.register(ObjectStorage, { useFactory: () => mockObjectStorage });
50
- injector.register(GenkitModuleOptions, { useValue: {} });
51
- injector.register(DocumentManagementAiService, { useValue: mockAiService });
52
- configureDocumentManagement({
53
- ancillaryService: TestDocumentManagementAncillaryService,
54
- authorizationService: TestDocumentManagementAuthorizationService,
55
- fileObjectStorageModule: 'documents',
56
- fileUploadObjectStorageModule: 'document-uploads',
57
- filePreviewObjectStorageModule: 'document-previews',
58
- injector,
59
- });
60
- documentService = await injector.resolveAsync(DocumentService);
61
- statsService = await injector.resolveAsync(DocumentStatisticsService);
62
- collectionService = await injector.resolveAsync(DocumentCollectionService);
63
- tagService = await injector.resolveAsync(DocumentTagService);
64
- categoryTypeService = await injector.resolveAsync(DocumentCategoryTypeService);
65
- });
66
- afterAll(async () => {
67
- await injector?.dispose();
68
- });
69
- beforeEach(async () => {
70
- await clearTenantData(database, schema, ['validation_execution', 'validation_definition', 'tag_assignment', 'collection_assignment', 'workflow', 'document', 'collection', 'tag', 'type', 'category'], tenantId);
71
- });
72
- test('getStatistics should return total count', async () => {
73
- await runInInjectionContext(injector, async () => {
74
- const collection = await collectionService.createCollection(tenantId, null);
75
- await documentService.create(tenantId, {
76
- title: 'Doc 1',
77
- assignment: { collections: [collection.id] },
78
- skipWorkflow: true,
79
- }, new Uint8Array([1]));
80
- await documentService.create(tenantId, {
81
- title: 'Doc 2',
82
- assignment: { collections: [collection.id] },
83
- skipWorkflow: true,
84
- }, new Uint8Array([1, 2]));
85
- const stats = await statsService.getStatistics(tenantId, { includeTotalCount: true, collectionIds: [collection.id] });
86
- expect(stats.totalCount).toBe(2);
87
- });
88
- });
89
- test('getStatistics should return approval breakdown', async () => {
90
- await runInInjectionContext(injector, async () => {
91
- const collection = await collectionService.createCollection(tenantId, null);
92
- await documentService.create(tenantId, {
93
- approval: DocumentApproval.Approved,
94
- assignment: { collections: [collection.id] },
95
- skipWorkflow: true,
96
- }, new Uint8Array([1]));
97
- await documentService.create(tenantId, {
98
- approval: DocumentApproval.Pending,
99
- assignment: { collections: [collection.id] },
100
- skipWorkflow: true,
101
- }, new Uint8Array([1]));
102
- await documentService.create(tenantId, {
103
- approval: DocumentApproval.Rejected,
104
- assignment: { collections: [collection.id] },
105
- skipWorkflow: true,
106
- }, new Uint8Array([1]));
107
- const stats = await statsService.getStatistics(tenantId, { includeApprovalBreakdown: true, collectionIds: [collection.id] });
108
- expect(stats.approvalBreakdown?.approved).toBe(1);
109
- expect(stats.approvalBreakdown?.pending).toBe(1);
110
- expect(stats.approvalBreakdown?.rejected).toBe(1);
111
- });
112
- });
113
- test('getStatistics should filter by collection', async () => {
114
- await runInInjectionContext(injector, async () => {
115
- const collection1 = await collectionService.createCollection(tenantId, null);
116
- const collection2 = await collectionService.createCollection(tenantId, null);
117
- await documentService.create(tenantId, {
118
- assignment: { collections: [collection1.id] },
119
- skipWorkflow: true,
120
- }, new Uint8Array([1]));
121
- await documentService.create(tenantId, {
122
- assignment: { collections: [collection2.id] },
123
- skipWorkflow: true,
124
- }, new Uint8Array([1]));
125
- const stats = await statsService.getStatistics(tenantId, { includeTotalCount: true, collectionIds: [collection1.id] });
126
- expect(stats.totalCount).toBe(1);
127
- });
128
- });
129
- test('getStatistics should return storage usage and total pages', async () => {
130
- await runInInjectionContext(injector, async () => {
131
- const collection = await collectionService.createCollection(tenantId, null);
132
- const doc = await documentService.create(tenantId, {
133
- assignment: { collections: [collection.id] },
134
- skipWorkflow: true,
135
- }, new Uint8Array([1, 2, 3])); // Size 3
136
- // Manually set pages since our mock doesn't handle PDF page count
137
- await documentService.repository.update(doc.id, { pages: 5 });
138
- const stats = await statsService.getStatistics(tenantId, { includeStorageUsage: true, includeTotalPages: true, collectionIds: [collection.id] });
139
- expect(stats.storageUsage).toBe(3);
140
- expect(stats.totalPages).toBe(5);
141
- });
142
- });
143
- test('getStatistics should return data quality metrics', async () => {
144
- await runInInjectionContext(injector, async () => {
145
- const collection = await collectionService.createCollection(tenantId, null);
146
- // Missing nothing (except type, which is checked separately)
147
- await documentService.create(tenantId, {
148
- assignment: { collections: [collection.id] },
149
- skipWorkflow: true,
150
- title: 'Title',
151
- date: 20230101,
152
- }, new Uint8Array([1]));
153
- // Missing title and date
154
- await documentService.create(tenantId, {
155
- assignment: { collections: [collection.id] },
156
- skipWorkflow: true,
157
- }, new Uint8Array([1]));
158
- const stats = await statsService.getStatistics(tenantId, { includeDataQuality: true, collectionIds: [collection.id] });
159
- expect(stats.dataQuality?.missingTitle).toBe(1);
160
- expect(stats.dataQuality?.missingDate).toBe(1);
161
- expect(stats.dataQuality?.missingType).toBe(2);
162
- });
163
- });
164
- test('getStatistics should return created last 30 days', async () => {
165
- await runInInjectionContext(injector, async () => {
166
- const collection = await collectionService.createCollection(tenantId, null);
167
- await documentService.create(tenantId, {
168
- assignment: { collections: [collection.id] },
169
- skipWorkflow: true,
170
- }, new Uint8Array([1]));
171
- const stats = await statsService.getStatistics(tenantId, { includeCreatedLast30Days: true, collectionIds: [collection.id] });
172
- expect(stats.createdLast30Days).toBe(1);
173
- });
174
- });
175
- test('getStatistics should return tag usage', async () => {
176
- await runInInjectionContext(injector, async () => {
177
- const collection = await collectionService.createCollection(tenantId, null);
178
- await documentService.create(tenantId, {
179
- assignment: { collections: [collection.id] },
180
- skipWorkflow: true,
181
- tags: ['Tag1'],
182
- }, new Uint8Array([1]));
183
- const [tag] = await tagService.loadOrCreate(tenantId, ['Tag1']);
184
- const stats = await statsService.getStatistics(tenantId, { includeTagUsage: true, collectionIds: [collection.id] });
185
- expect(stats.tagUsage?.[tag.id]).toBe(1);
186
- });
187
- });
188
- test('getStatistics should return mime type distribution', async () => {
189
- await runInInjectionContext(injector, async () => {
190
- const collection = await collectionService.createCollection(tenantId, null);
191
- await documentService.create(tenantId, {
192
- assignment: { collections: [collection.id] },
193
- skipWorkflow: true,
194
- }, new Uint8Array([1]));
195
- const stats = await statsService.getStatistics(tenantId, { includeMimeTypeDistribution: true, collectionIds: [collection.id] });
196
- expect(Object.keys(stats.mimeTypeDistribution ?? {}).length).toBeGreaterThan(0);
197
- });
198
- });
199
- test('getStatistics should return type breakdown and filter by category', async () => {
200
- await runInInjectionContext(injector, async () => {
201
- const collection = await collectionService.createCollection(tenantId, null);
202
- const categoryLabel = `Category ${crypto.randomUUID()}`;
203
- const category = await categoryTypeService.createCategory({ tenantId, label: categoryLabel, parentId: null });
204
- const type = await categoryTypeService.createType({ tenantId, label: 'Type 1', categoryId: category.id });
205
- await documentService.create(tenantId, {
206
- assignment: { collections: [collection.id] },
207
- skipWorkflow: true,
208
- typeId: type.id,
209
- }, new Uint8Array([1]));
210
- const stats = await statsService.getStatistics(tenantId, { includeTypeBreakdown: true, collectionIds: [collection.id], categoryIds: [category.id] });
211
- expect(stats.typeBreakdown?.[type.id]).toBe(1);
212
- });
213
- });
214
- test('getStatistics should return validation failures', async () => {
215
- await runInInjectionContext(injector, async () => {
216
- const collection = await collectionService.createCollection(tenantId, null);
217
- const doc = await documentService.create(tenantId, {
218
- assignment: { collections: [collection.id] },
219
- skipWorkflow: true,
220
- }, new Uint8Array([1]));
221
- const workflowRepo = await injector.resolveAsync(getRepository(DocumentWorkflow));
222
- const validationRepo = await injector.resolveAsync(getRepository(DocumentValidationExecution));
223
- const definitionRepo = await injector.resolveAsync(getRepository(DocumentValidationDefinition));
224
- const definition = await definitionRepo.insert({
225
- tenantId,
226
- identifier: 'test-val',
227
- label: 'Test Validation',
228
- description: null,
229
- configuration: {},
230
- });
231
- const workflow = await workflowRepo.insert({
232
- tenantId,
233
- documentId: doc.id,
234
- step: DocumentWorkflowStep.Validation,
235
- state: DocumentWorkflowState.Pending,
236
- skipAi: true,
237
- completeTimestamp: null,
238
- failReason: null,
239
- completeUserId: null,
240
- });
241
- await validationRepo.insert({
242
- tenantId,
243
- workflowId: workflow.id,
244
- definitionId: definition.id,
245
- state: DocumentValidationExecutionState.Completed,
246
- resultStatus: DocumentValidationResultStatus.Failed,
247
- resultMessage: null,
248
- startedAt: null,
249
- completedAt: null,
250
- });
251
- const stats = await statsService.getStatistics(tenantId, { includeValidationFailures: true, collectionIds: [collection.id] });
252
- expect(stats.validationFailures).toBe(1);
253
- });
254
- });
255
- test('getStatistics should return nothing when no options selected', async () => {
256
- await runInInjectionContext(injector, async () => {
257
- const stats = await statsService.getStatistics(tenantId, { collectionIds: [] });
258
- expect(Object.keys(stats).length).toBe(0);
259
- });
260
- });
261
- test('getStatistics should support combined filters', async () => {
262
- await runInInjectionContext(injector, async () => {
263
- const collection1 = await collectionService.createCollection(tenantId, null);
264
- const collection2 = await collectionService.createCollection(tenantId, null);
265
- const category1 = await categoryTypeService.createCategory({ tenantId, label: `Cat 1 ${crypto.randomUUID()}`, parentId: null });
266
- const category2 = await categoryTypeService.createCategory({ tenantId, label: `Cat 2 ${crypto.randomUUID()}`, parentId: null });
267
- const type1 = await categoryTypeService.createType({ tenantId, label: 'Type 1', categoryId: category1.id });
268
- const type2 = await categoryTypeService.createType({ tenantId, label: 'Type 2', categoryId: category2.id });
269
- // Doc 1: Coll 1, Type 1 (Cat 1)
270
- await documentService.create(tenantId, {
271
- assignment: { collections: [collection1.id] },
272
- typeId: type1.id,
273
- skipWorkflow: true,
274
- }, new Uint8Array([1]));
275
- // Doc 2: Coll 1, Type 2 (Cat 2)
276
- await documentService.create(tenantId, {
277
- assignment: { collections: [collection1.id] },
278
- typeId: type2.id,
279
- skipWorkflow: true,
280
- }, new Uint8Array([1]));
281
- // Doc 3: Coll 2, Type 1 (Cat 1)
282
- await documentService.create(tenantId, {
283
- assignment: { collections: [collection2.id] },
284
- typeId: type1.id,
285
- skipWorkflow: true,
286
- }, new Uint8Array([1]));
287
- const stats = await statsService.getStatistics(tenantId, {
288
- includeTotalCount: true,
289
- collectionIds: [collection1.id],
290
- categoryIds: [category1.id],
291
- });
292
- expect(stats.totalCount).toBe(1); // Only Doc 1 matches both
293
- });
294
- });
295
- test('getStatistics should return multiple stats without category filters', async () => {
296
- await runInInjectionContext(injector, async () => {
297
- const collection = await collectionService.createCollection(tenantId, null);
298
- const category = await categoryTypeService.createCategory({ tenantId, label: `Cat ${crypto.randomUUID()}`, parentId: null });
299
- const type = await categoryTypeService.createType({ tenantId, label: 'Type', categoryId: category.id });
300
- await documentService.create(tenantId, {
301
- assignment: { collections: [collection.id] },
302
- typeId: type.id,
303
- skipWorkflow: true,
304
- title: 'Title',
305
- }, new Uint8Array([1, 2, 3]));
306
- const stats = await statsService.getStatistics(tenantId, {
307
- includeTotalCount: true,
308
- includeTypeBreakdown: true,
309
- includeMimeTypeDistribution: true,
310
- includeStorageUsage: true,
311
- includeDataQuality: true,
312
- collectionIds: [collection.id],
313
- });
314
- expect(stats.totalCount).toBe(1);
315
- expect(stats.typeBreakdown?.[type.id]).toBe(1);
316
- expect(stats.storageUsage).toBe(3);
317
- expect(stats.dataQuality?.missingTitle).toBe(0);
318
- });
319
- });
320
- test('getStatistics should return stats with only collection filter', async () => {
321
- await runInInjectionContext(injector, async () => {
322
- const collection = await collectionService.createCollection(tenantId, null);
323
- await documentService.create(tenantId, {
324
- assignment: { collections: [collection.id] },
325
- skipWorkflow: true,
326
- }, new Uint8Array([1]));
327
- const stats = await statsService.getStatistics(tenantId, {
328
- includeTotalCount: true,
329
- includeMimeTypeDistribution: true,
330
- collectionIds: [collection.id],
331
- });
332
- expect(stats.totalCount).toBe(1);
333
- });
334
- });
335
- test('getStatistics should return mime type distribution with category filter', async () => {
336
- await runInInjectionContext(injector, async () => {
337
- const collection = await collectionService.createCollection(tenantId, null);
338
- const category = await categoryTypeService.createCategory({ tenantId, label: `Cat ${crypto.randomUUID()}`, parentId: null });
339
- const type = await categoryTypeService.createType({ tenantId, label: 'Type', categoryId: category.id });
340
- await documentService.create(tenantId, {
341
- assignment: { collections: [collection.id] },
342
- typeId: type.id,
343
- skipWorkflow: true,
344
- }, new Uint8Array([1]));
345
- const stats = await statsService.getStatistics(tenantId, {
346
- includeMimeTypeDistribution: true,
347
- collectionIds: [collection.id],
348
- categoryIds: [category.id],
349
- });
350
- expect(Object.keys(stats.mimeTypeDistribution ?? {}).length).toBeGreaterThan(0);
351
- });
352
- });
353
- test('getStatistics should return tag usage with filters', async () => {
354
- await runInInjectionContext(injector, async () => {
355
- const collection = await collectionService.createCollection(tenantId, null);
356
- const category = await categoryTypeService.createCategory({ tenantId, label: `Cat ${crypto.randomUUID()}`, parentId: null });
357
- const type = await categoryTypeService.createType({ tenantId, label: 'Type', categoryId: category.id });
358
- await documentService.create(tenantId, {
359
- assignment: { collections: [collection.id] },
360
- typeId: type.id,
361
- skipWorkflow: true,
362
- tags: ['Tag1'],
363
- }, new Uint8Array([1]));
364
- const [tag] = await tagService.loadOrCreate(tenantId, ['Tag1']);
365
- const stats = await statsService.getStatistics(tenantId, {
366
- includeTagUsage: true,
367
- collectionIds: [collection.id],
368
- categoryIds: [category.id],
369
- });
370
- expect(stats.tagUsage?.[tag.id]).toBe(1);
371
- });
372
- });
373
- test('getStatistics should return validation failures with collection filter', async () => {
374
- await runInInjectionContext(injector, async () => {
375
- const collection = await collectionService.createCollection(tenantId, null);
376
- const doc = await documentService.create(tenantId, {
377
- assignment: { collections: [collection.id] },
378
- skipWorkflow: true,
379
- }, new Uint8Array([1]));
380
- const workflowRepo = await injector.resolveAsync(getRepository(DocumentWorkflow));
381
- const validationRepo = await injector.resolveAsync(getRepository(DocumentValidationExecution));
382
- const definitionRepo = await injector.resolveAsync(getRepository(DocumentValidationDefinition));
383
- const definition = await definitionRepo.insert({
384
- tenantId,
385
- identifier: 'test-val-2',
386
- label: 'Test Validation',
387
- description: null,
388
- configuration: {},
389
- });
390
- const workflow = await workflowRepo.insert({
391
- tenantId,
392
- documentId: doc.id,
393
- step: DocumentWorkflowStep.Validation,
394
- state: DocumentWorkflowState.Pending,
395
- skipAi: true,
396
- completeTimestamp: null,
397
- failReason: null,
398
- completeUserId: null,
399
- });
400
- await validationRepo.insert({
401
- tenantId,
402
- workflowId: workflow.id,
403
- definitionId: definition.id,
404
- state: DocumentValidationExecutionState.Completed,
405
- resultStatus: DocumentValidationResultStatus.Failed,
406
- resultMessage: null,
407
- startedAt: null,
408
- completedAt: null,
409
- });
410
- const stats = await statsService.getStatistics(tenantId, {
411
- includeValidationFailures: true,
412
- collectionIds: [collection.id],
413
- });
414
- expect(stats.validationFailures).toBe(1);
415
- });
416
- });
417
- test('getStatistics should return validation failures with category filter', async () => {
418
- await runInInjectionContext(injector, async () => {
419
- const categoryLabel = `Cat val ${crypto.randomUUID()}`;
420
- const category = await categoryTypeService.createCategory({ tenantId, label: categoryLabel, parentId: null });
421
- const type = await categoryTypeService.createType({ tenantId, label: 'Type val', categoryId: category.id });
422
- const collection = await collectionService.createCollection(tenantId, null);
423
- const doc = await documentService.create(tenantId, {
424
- assignment: { collections: [collection.id] },
425
- typeId: type.id,
426
- skipWorkflow: true,
427
- }, new Uint8Array([1]));
428
- const workflowRepo = await injector.resolveAsync(getRepository(DocumentWorkflow));
429
- const validationRepo = await injector.resolveAsync(getRepository(DocumentValidationExecution));
430
- const definitionRepo = await injector.resolveAsync(getRepository(DocumentValidationDefinition));
431
- const definition = await definitionRepo.insert({
432
- tenantId,
433
- identifier: 'test-val-3',
434
- label: 'Test Validation',
435
- description: null,
436
- configuration: {},
437
- });
438
- const workflow = await workflowRepo.insert({
439
- tenantId,
440
- documentId: doc.id,
441
- step: DocumentWorkflowStep.Validation,
442
- state: DocumentWorkflowState.Pending,
443
- skipAi: true,
444
- completeTimestamp: null,
445
- failReason: null,
446
- completeUserId: null,
447
- });
448
- await validationRepo.insert({
449
- tenantId,
450
- workflowId: workflow.id,
451
- definitionId: definition.id,
452
- state: DocumentValidationExecutionState.Completed,
453
- resultStatus: DocumentValidationResultStatus.Failed,
454
- resultMessage: null,
455
- startedAt: null,
456
- completedAt: null,
457
- });
458
- const stats = await statsService.getStatistics(tenantId, {
459
- includeValidationFailures: true,
460
- collectionIds: [collection.id],
461
- categoryIds: [category.id],
462
- });
463
- expect(stats.validationFailures).toBe(1);
464
- });
465
- });
466
- test('getStatistics should return type breakdown with collection filter', async () => {
467
- await runInInjectionContext(injector, async () => {
468
- const collection = await collectionService.createCollection(tenantId, null);
469
- const category = await categoryTypeService.createCategory({ tenantId, label: `Cat ${crypto.randomUUID()}`, parentId: null });
470
- const type = await categoryTypeService.createType({ tenantId, label: 'Type', categoryId: category.id });
471
- await documentService.create(tenantId, {
472
- assignment: { collections: [collection.id] },
473
- typeId: type.id,
474
- skipWorkflow: true,
475
- }, new Uint8Array([1]));
476
- const stats = await statsService.getStatistics(tenantId, {
477
- includeTypeBreakdown: true,
478
- collectionIds: [collection.id],
479
- });
480
- expect(stats.typeBreakdown?.[type.id]).toBe(1);
481
- });
482
- });
483
- test('getStatistics should return zeroed stats for empty tenant', async () => {
484
- await runInInjectionContext(injector, async () => {
485
- const stats = await statsService.getStatistics(tenantId, {
486
- includeTotalCount: true,
487
- includeStorageUsage: true,
488
- includeTotalPages: true,
489
- includeValidationFailures: true,
490
- collectionIds: [],
491
- });
492
- expect(stats.totalCount).toBe(0);
493
- expect(stats.storageUsage).toBe(0);
494
- expect(stats.totalPages).toBe(0);
495
- expect(stats.validationFailures).toBe(0);
496
- });
497
- });
498
- });