@futdevpro/nts-dynamo 1.15.92 → 1.15.94

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 (381) hide show
  1. package/.c8rc.json +26 -26
  2. package/.copilot/patterns.json +7 -7
  3. package/.cursor/rules/__assistant_guide.mdc +30 -30
  4. package/.cursor/rules/_ag_backend-structure.mdc +85 -85
  5. package/.cursor/rules/_ag_backend.mdc +16 -16
  6. package/.cursor/rules/_ag_frontend-structure.mdc +86 -86
  7. package/.cursor/rules/_ag_frontend.mdc +39 -39
  8. package/.cursor/rules/_ag_import-rules.mdc +44 -44
  9. package/.cursor/rules/_ag_naming.mdc +115 -115
  10. package/.cursor/rules/_ag_should-be.mdc +6 -6
  11. package/.cursor/rules/ai_development_guide.md +60 -60
  12. package/.cursor/rules/cursor-rules.md +160 -160
  13. package/.cursor/rules/default-command.mdc +464 -464
  14. package/.cursor/rules/error_code_pattern.md +39 -39
  15. package/.cursor/rules/saved rule mcp server use.md +15 -15
  16. package/.vscode/settings.json +10 -10
  17. package/HOWTO.md +15 -15
  18. package/LICENSE +21 -21
  19. package/__documentations/nts-integration-tests-2026-03-17.md +26 -26
  20. package/__documentations/plans/BEDROCK-HYPERPLAN.md +95 -95
  21. package/_specifications/BACKLOG.md +92 -92
  22. package/_specifications/TODO.md +15 -15
  23. package/_specifications/agent.md +138 -138
  24. package/build/_models/interfaces/db-query-options.interface.d.ts +33 -0
  25. package/build/_models/interfaces/db-query-options.interface.d.ts.map +1 -0
  26. package/build/_models/interfaces/db-query-options.interface.js +3 -0
  27. package/build/_models/interfaces/db-query-options.interface.js.map +1 -0
  28. package/build/_services/base/data.service.d.ts +3 -1
  29. package/build/_services/base/data.service.d.ts.map +1 -1
  30. package/build/_services/base/data.service.js +5 -2
  31. package/build/_services/base/data.service.js.map +1 -1
  32. package/build/_services/base/db.service.d.ts +3 -1
  33. package/build/_services/base/db.service.d.ts.map +1 -1
  34. package/build/_services/base/db.service.js +23 -4
  35. package/build/_services/base/db.service.js.map +1 -1
  36. package/build/index.d.ts +1 -0
  37. package/build/index.d.ts.map +1 -1
  38. package/build/index.js +1 -0
  39. package/build/index.js.map +1 -1
  40. package/eslint.config.js +3 -3
  41. package/nodemon.json +24 -24
  42. package/package.json +1 -1
  43. package/pnpm-workspace.yaml +5 -5
  44. package/scripts/run-coverage-tests.js +28 -28
  45. package/spec/support/helpers/spec-reporter-loader.js +359 -359
  46. package/spec/support/helpers/ts-node-helper.js +93 -93
  47. package/spec/support/jasmine.coverage.json +24 -24
  48. package/spec/support/jasmine.json +24 -24
  49. package/src/_collections/archive.util.spec.ts +57 -57
  50. package/src/_collections/archive.util.ts +18 -18
  51. package/src/_collections/atlas-default-db-options.const.ts +9 -9
  52. package/src/_collections/default-fallback-cache-max-age.const.spec.ts +11 -11
  53. package/src/_collections/default-fallback-cache-max-age.const.ts +2 -2
  54. package/src/_collections/default-not-found-page.const.spec.ts +19 -19
  55. package/src/_collections/default-not-found-page.const.ts +22 -22
  56. package/src/_collections/default-socket-path.const.spec.ts +12 -12
  57. package/src/_collections/default-socket-path.const.ts +2 -2
  58. package/src/_collections/get-environment-settings.util.spec.ts +210 -210
  59. package/src/_collections/get-environment-settings.util.ts +48 -48
  60. package/src/_collections/global-settings.const.ts +109 -109
  61. package/src/_collections/sample.env +21 -21
  62. package/src/_collections/star.controller.spec.ts +224 -224
  63. package/src/_collections/star.controller.ts +129 -129
  64. package/src/_enums/data-model-type.enum.ts +14 -14
  65. package/src/_enums/data-service-function.enum.ts +24 -24
  66. package/src/_enums/predefined-data-types.enum.ts +16 -16
  67. package/src/_enums/route-security.enum.ts +12 -12
  68. package/src/_models/control-models/api-call-params.control-model.spec.ts +152 -152
  69. package/src/_models/control-models/api-call-params.control-model.ts +142 -142
  70. package/src/_models/control-models/app-ext-system-controls.control-model.spec.ts +52 -52
  71. package/src/_models/control-models/app-ext-system-controls.control-model.ts +9 -9
  72. package/src/_models/control-models/app-params.control-model.spec.ts +225 -225
  73. package/src/_models/control-models/app-params.control-model.ts +136 -136
  74. package/src/_models/control-models/app-system-controls.control-model.spec.ts +31 -31
  75. package/src/_models/control-models/app-system-controls.control-model.ts +9 -9
  76. package/src/_models/control-models/endpoint-params.control-model.spec.ts +627 -627
  77. package/src/_models/control-models/endpoint-params.control-model.ts +627 -627
  78. package/src/_models/control-models/http-settings.control-model.spec.ts +77 -77
  79. package/src/_models/control-models/http-settings.control-model.ts +37 -37
  80. package/src/_models/control-models/system-control.control-model.spec.ts +27 -27
  81. package/src/_models/control-models/system-control.control-model.ts +12 -12
  82. package/src/_models/interfaces/certification-settings.interface.ts +7 -7
  83. package/src/_models/interfaces/db-query-options.interface.ts +33 -0
  84. package/src/_models/interfaces/environment-settings.interface.ts +59 -59
  85. package/src/_models/interfaces/global-log-settings.interface.ts +171 -171
  86. package/src/_models/interfaces/global-service-settings.interface.ts +47 -47
  87. package/src/_models/interfaces/global-settings.interface.ts +244 -244
  88. package/src/_models/interfaces/routing-module-settings.interface.ts +21 -21
  89. package/src/_models/interfaces/static-client-settings.interface.spec.ts +29 -29
  90. package/src/_models/interfaces/static-client-settings.interface.ts +28 -28
  91. package/src/_models/types/db-update.type.ts +100 -100
  92. package/src/_modules/ai/_models/ai-input-interfaces.ts +117 -117
  93. package/src/_modules/ai/_models/ai-test-generation-result.interface.ts +16 -16
  94. package/src/_modules/ai/_modules/anthropic/_services/aai-user-key.control-service.ts +138 -138
  95. package/src/_modules/ai/_modules/anthropic/index.ts +5 -5
  96. package/src/_modules/ai/_modules/document-ai/_collections/dai-chunking.util.spec.ts +242 -242
  97. package/src/_modules/ai/_modules/document-ai/_collections/dai-chunking.util.ts +639 -639
  98. package/src/_modules/ai/_modules/document-ai/_collections/dai-code-chunking.util.spec.ts +295 -295
  99. package/src/_modules/ai/_modules/document-ai/_collections/dai-code-chunking.util.ts +518 -518
  100. package/src/_modules/ai/_modules/document-ai/_collections/dai-document.util.spec.ts +209 -209
  101. package/src/_modules/ai/_modules/document-ai/_collections/dai-document.util.ts +85 -85
  102. package/src/_modules/ai/_modules/document-ai/_enums/dai-compare-result-type.enum.ts +7 -7
  103. package/src/_modules/ai/_modules/document-ai/_models/data-models/dai-doc-chunk.data-model.ts +146 -146
  104. package/src/_modules/ai/_modules/document-ai/_models/data-models/dai-doc-page.data-model.ts +162 -162
  105. package/src/_modules/ai/_modules/document-ai/_models/data-models/dai-document.data-model.ts +99 -99
  106. package/src/_modules/ai/_modules/document-ai/_models/interfaces/dai-code-chunk.interface.ts +68 -68
  107. package/src/_modules/ai/_modules/document-ai/_models/interfaces/dai-doc-chunk-compare-result.interface.ts +18 -18
  108. package/src/_modules/ai/_modules/document-ai/_models/interfaces/dai-doc-page-compare-result.interface.ts +19 -19
  109. package/src/_modules/ai/_modules/document-ai/_models/interfaces/dai-document-compare-result.interface.ts +25 -25
  110. package/src/_modules/ai/_modules/document-ai/index.ts +30 -30
  111. package/src/_modules/ai/_modules/fdp-ai/_services/fdpai-user-key.control-service.ts +189 -189
  112. package/src/_modules/ai/_modules/fdp-ai/index.ts +5 -5
  113. package/src/_modules/ai/_modules/open-ai/_collections/oai-global-settings.const.ts +9 -9
  114. package/src/_modules/ai/_modules/open-ai/_collections/oai-llm-predefined-requests-hu.conts.ts +82 -82
  115. package/src/_modules/ai/_modules/open-ai/_collections/oai-llm-predefined-requests.conts.ts +75 -75
  116. package/src/_modules/ai/_modules/open-ai/_enums/oai-gpt-message-role.enum.ts +45 -45
  117. package/src/_modules/ai/_modules/open-ai/_models/interfaces/oai-global-settings.interface.ts +7 -7
  118. package/src/_modules/ai/_modules/open-ai/_models/interfaces/oai-gpt-message.interface.ts +7 -7
  119. package/src/_modules/ai/_modules/open-ai/_models/interfaces/oai-llm-predefined-requests.interface.ts +57 -57
  120. package/src/_modules/ai/_modules/open-ai/_services/data-services/oai-doc-chunk-data.service.ts +292 -292
  121. package/src/_modules/ai/_modules/open-ai/_services/data-services/oai-document.data-service.spec.ts +342 -342
  122. package/src/_modules/ai/_modules/open-ai/_services/data-services/oai-vector-data.service.spec.ts +550 -550
  123. package/src/_modules/ai/_modules/open-ai/_services/data-services/oai-vector-data.service.ts +630 -630
  124. package/src/_modules/ai/_modules/open-ai/_services/oai-embedding.control-service.spec.ts +332 -332
  125. package/src/_modules/ai/_modules/open-ai/_services/oai-llm-chat.service-base.spec.ts +462 -462
  126. package/src/_modules/ai/_modules/open-ai/_services/oai-llm-chat.service-base.ts +634 -634
  127. package/src/_modules/ai/_modules/open-ai/_services/oai-llm.service-base.spec.ts +489 -489
  128. package/src/_modules/ai/_modules/open-ai/_services/oai-llm.service-base.tools.spec.ts +173 -173
  129. package/src/_modules/ai/_modules/open-ai/_services/oai-llm.service-base.ts +1033 -1033
  130. package/src/_modules/ai/_modules/open-ai/_services/oai-user-key.control-service.ts +157 -157
  131. package/src/_modules/ai/_services/ai-embedding-mock.service.spec.ts +115 -115
  132. package/src/_modules/ai/_services/ai-embedding-mock.service.ts +212 -212
  133. package/src/_modules/ai/_services/ai-embedding-provider.registry.spec.ts +110 -110
  134. package/src/_modules/ai/_services/ai-embedding-provider.registry.ts +110 -110
  135. package/src/_modules/ai/_services/ai-embedding.service-base.spec.ts +98 -98
  136. package/src/_modules/ai/_services/ai-embedding.service-base.ts +48 -48
  137. package/src/_modules/ai/_services/ai-llm-chat.service-base.spec.ts +229 -229
  138. package/src/_modules/ai/_services/ai-llm-chat.service-base.ts +68 -68
  139. package/src/_modules/ai/_services/ai-llm.service-base.spec.ts +250 -250
  140. package/src/_modules/ai/_services/ai-llm.service-base.ts +519 -519
  141. package/src/_modules/ai/_services/ai-provider.service-base.spec.ts +158 -158
  142. package/src/_modules/ai/_services/ai-user-key.service-base.ts +59 -59
  143. package/src/_modules/ai/_services/lmstudio-embedding.control-service.spec.ts +197 -197
  144. package/src/_modules/ai/_services/lmstudio-embedding.control-service.ts +371 -371
  145. package/src/_modules/ai/index.ts +23 -23
  146. package/src/_modules/assistant/_collections/ass-global-settings.const.ts +13 -13
  147. package/src/_modules/assistant/_collections/ass.util.spec.ts +176 -176
  148. package/src/_modules/assistant/_collections/ass.util.ts +50 -50
  149. package/src/_modules/assistant/_models/ass-global-settings.interface.ts +15 -15
  150. package/src/_modules/assistant/_services/ass-io.control-service.spec.ts +140 -140
  151. package/src/_modules/assistant/_services/ass-main.control-service.spec.ts +192 -192
  152. package/src/_modules/assistant/_services/ass-main.control-service.ts +107 -107
  153. package/src/_modules/bot/_collections/bot-default-commands.const.ts +12 -12
  154. package/src/_modules/bot/_collections/bot-global-settings.const.ts +39 -39
  155. package/src/_modules/bot/_models/bot-channel-wrapper.interface.ts +62 -62
  156. package/src/_modules/bot/_models/bot-command.interface.ts +8 -8
  157. package/src/_modules/bot/_models/bot-global-settings.interface.ts +96 -96
  158. package/src/_modules/bot/_models/bot-last-mention-date.interface.ts +6 -6
  159. package/src/_modules/bot/_models/bot-last-message-date.interface.ts +5 -5
  160. package/src/_modules/bot/_models/bot-user-wrapper.interface.ts +41 -41
  161. package/src/_modules/bot/_modules/discord-bot/_models/dib-platform.types.ts +9 -9
  162. package/src/_modules/bot/_modules/discord-bot/_services/dib-messaging-provider.control-service.spec.ts +431 -431
  163. package/src/_modules/bot/_modules/dynamo-bot/_collections/dyb-operations.util.spec.ts +160 -160
  164. package/src/_modules/bot/_modules/dynamo-bot/_collections/dyb-operations.util.ts +55 -55
  165. package/src/_modules/bot/_modules/dynamo-bot/_models/dyb-platform.types.ts +15 -15
  166. package/src/_modules/bot/_modules/dynamo-bot/_services/dyb-messaging-provider.control-service.spec.ts +374 -374
  167. package/src/_modules/bot/_modules/dynamo-bot/_services/dyb-messaging-provider.control-service.ts +447 -447
  168. package/src/_modules/bot/_modules/dynamo-bot/index.ts +15 -15
  169. package/src/_modules/bot/_modules/slack-bot/_models/slb-platform.types.ts +9 -9
  170. package/src/_modules/bot/_modules/slack-bot/_services/slb-messaging-provider.control-service.spec.ts +344 -344
  171. package/src/_modules/bot/_modules/slack-bot/_services/slb-messaging-provider.control-service.ts +197 -197
  172. package/src/_modules/bot/_modules/teams-bot/_models/teb-platform.types.ts +9 -9
  173. package/src/_modules/bot/_modules/teams-bot/_services/teb-messaging-provider.control-service.spec.ts +345 -345
  174. package/src/_modules/bot/_modules/teams-bot/_services/teb-messaging-provider.control-service.ts +197 -197
  175. package/src/_modules/bot/_services/bot-commands.control-service.spec.ts +116 -116
  176. package/src/_modules/bot/_services/bot-io.control-service.spec.ts +285 -285
  177. package/src/_modules/bot/_services/bot-main.control-service.spec.ts +208 -208
  178. package/src/_modules/bot/_services/bot-messaging-provider.service-base.spec.ts +349 -349
  179. package/src/_modules/bot/_services/bot-routines.control-service.spec.ts +111 -111
  180. package/src/_modules/custom-data/custom-data.controller.spec.ts +49 -49
  181. package/src/_modules/custom-data/custom-data.controller.ts +67 -67
  182. package/src/_modules/custom-data/custom-data.data-service.spec.ts +54 -54
  183. package/src/_modules/custom-data/custom-data.data-service.ts +21 -21
  184. package/src/_modules/custom-data/get-custom-data-routing-module.util.spec.ts +28 -28
  185. package/src/_modules/custom-data/get-custom-data-routing-module.util.ts +24 -24
  186. package/src/_modules/custom-data/index.ts +9 -9
  187. package/src/_modules/data-readers/_collections/dynts-sqlite-reader.util.spec.ts +161 -161
  188. package/src/_modules/data-readers/_collections/dynts-sqlite-reader.util.ts +203 -203
  189. package/src/_modules/data-readers/_models/interfaces/dynts-sqlite-reader.interface.ts +33 -33
  190. package/src/_modules/data-readers/index.ts +11 -11
  191. package/src/_modules/defaults/_collections/default-endpoints.util.ts +487 -487
  192. package/src/_modules/defaults/_models/default-user.data-model.ts +72 -72
  193. package/src/_modules/defaults/_services/default-auth.service.spec.ts +269 -269
  194. package/src/_modules/defaults/_services/default-auth.service.ts +177 -177
  195. package/src/_modules/defaults/_services/default-socket-events.service.spec.ts +42 -42
  196. package/src/_modules/defaults/_services/default-socket-events.service.ts +61 -61
  197. package/src/_modules/defaults/_services/default-user.data-service.spec.ts +187 -187
  198. package/src/_modules/defaults/_services/default-user.data-service.ts +98 -98
  199. package/src/_modules/defaults/index.ts +17 -17
  200. package/src/_modules/discord-assistant/_collections/dias-global-settings.const.ts +19 -19
  201. package/src/_modules/discord-assistant/_collections/dias.util.spec.ts +366 -366
  202. package/src/_modules/discord-assistant/_collections/dias.util.ts +132 -132
  203. package/src/_modules/discord-assistant/_models/dias-global-settings.interface.ts +19 -19
  204. package/src/_modules/discord-assistant/_models/dias-knowledge.data-model.ts +52 -52
  205. package/src/_modules/discord-assistant/_services/dias-chunk.data-service.ts +177 -177
  206. package/src/_modules/discord-assistant/_services/dias-io.control-service.spec.ts +108 -108
  207. package/src/_modules/discord-assistant/_services/dias-io.control-service.ts +69 -69
  208. package/src/_modules/discord-assistant/_services/dias-main.control-service.spec.ts +22 -22
  209. package/src/_modules/discord-assistant/_services/dias-main.control-service.ts +27 -27
  210. package/src/_modules/discord-assistant/_services/dias.service-base.spec.ts +195 -195
  211. package/src/_modules/discord-assistant/_services/dias.service-base.ts +76 -76
  212. package/src/_modules/discord-assistant/index.ts +38 -38
  213. package/src/_modules/discord-assistant-voiced/_services/dias-discord-bot.control-service.spec.ts +34 -34
  214. package/src/_modules/discord-assistant-voiced/_services/dias-discord-bot.control-service.ts +11 -11
  215. package/src/_modules/discord-assistant-voiced/index.ts +36 -36
  216. package/src/_modules/discord-bot/_collections/dibo-default-commands.const.ts +16 -16
  217. package/src/_modules/discord-bot/_collections/dibo-global-settings.conts.ts +55 -55
  218. package/src/_modules/discord-bot/_collections/dibo-operations.util.spec.ts +214 -214
  219. package/src/_modules/discord-bot/_collections/dibo-operations.util.ts +387 -387
  220. package/src/_modules/discord-bot/_models/dibo-command.interface.ts +12 -12
  221. package/src/_modules/discord-bot/_models/dibo-global-settings.interface.ts +98 -98
  222. package/src/_modules/discord-bot/_models/dibo-last-mention-date.inteface.ts +7 -7
  223. package/src/_modules/discord-bot/_models/dibo-last-message-date.interface.ts +6 -6
  224. package/src/_modules/discord-bot/_services/dibo-commands.control-service.spec.ts +154 -154
  225. package/src/_modules/discord-bot/_services/dibo-commands.control-service.ts +153 -153
  226. package/src/_modules/discord-bot/_services/dibo-io.control-service.spec.ts +264 -264
  227. package/src/_modules/discord-bot/_services/dibo-io.control-service.ts +306 -306
  228. package/src/_modules/discord-bot/_services/dibo-main.control-service.spec.ts +408 -408
  229. package/src/_modules/discord-bot/_services/dibo-main.control-service.ts +487 -487
  230. package/src/_modules/discord-bot/_services/dibo-routines.control-service.spec.ts +105 -105
  231. package/src/_modules/discord-bot/index.ts +36 -36
  232. package/src/_modules/local-vector-search/_enums/lvs-search-mode.enum.ts +35 -35
  233. package/src/_modules/local-vector-search/_models/data-models/lvs-vector-persist.data-model.ts +59 -59
  234. package/src/_modules/local-vector-search/_models/lvs-search-result.interface.ts +17 -17
  235. package/src/_modules/local-vector-search/_services/lvs-doc-chunk-data.service.spec.ts +418 -418
  236. package/src/_modules/local-vector-search/_services/lvs-doc-chunk-data.service.ts +276 -276
  237. package/src/_modules/local-vector-search/_services/lvs-local-vector-search.data-service.spec.ts +480 -480
  238. package/src/_modules/local-vector-search/_services/lvs-local-vector-search.data-service.ts +416 -416
  239. package/src/_modules/local-vector-search/_services/lvs-persistent-vector-pool.control-service.spec.ts +198 -198
  240. package/src/_modules/local-vector-search/_services/lvs-persistent-vector-pool.control-service.ts +146 -146
  241. package/src/_modules/local-vector-search/_services/lvs-vector-persist.data-service.spec.ts +167 -167
  242. package/src/_modules/local-vector-search/_services/lvs-vector-persist.data-service.ts +106 -106
  243. package/src/_modules/local-vector-search/_services/lvs-vector-pool.control-service.spec.ts +507 -507
  244. package/src/_modules/local-vector-search/_services/lvs-vector-pool.control-service.ts +272 -272
  245. package/src/_modules/local-vector-search/index.ts +16 -16
  246. package/src/_modules/logs/index.ts +11 -11
  247. package/src/_modules/mcp/_models/interfaces/dynts-mcp.interface.ts +111 -111
  248. package/src/_modules/mcp/_services/dynts-mcp-server.service-base.spec.ts +142 -142
  249. package/src/_modules/mcp/_services/dynts-mcp-server.service-base.ts +120 -120
  250. package/src/_modules/mcp/_services/dynts-mcp.adapter.ts +168 -168
  251. package/src/_modules/mcp/index.ts +13 -13
  252. package/src/_modules/messaging/README.md +354 -354
  253. package/src/_modules/messaging/_collections/get-messaging-routing-module.util.ts +26 -26
  254. package/src/_modules/messaging/_collections/msg-global-settings.const.ts +22 -22
  255. package/src/_modules/messaging/_collections/msg.util.spec.ts +226 -226
  256. package/src/_modules/messaging/_models/msg-global-settings.interface.ts +37 -37
  257. package/src/_modules/messaging/_services/msg-conversation.data-service.ts +146 -146
  258. package/src/_modules/messaging/_services/msg-events.service.spec.ts +219 -219
  259. package/src/_modules/messaging/_services/msg-events.service.ts +267 -267
  260. package/src/_modules/messaging/_services/msg-integration.control-service.ts +179 -179
  261. package/src/_modules/messaging/_services/msg-main.control-service.spec.ts +147 -147
  262. package/src/_modules/messaging/_services/msg-main.control-service.ts +571 -571
  263. package/src/_modules/messaging/_services/msg-message.data-service.ts +129 -129
  264. package/src/_modules/messaging/_services/msg.controller.spec.ts +201 -201
  265. package/src/_modules/messaging/index.ts +30 -30
  266. package/src/_modules/mock/app-extended-server.mock.ts +201 -201
  267. package/src/_modules/mock/app-integration-test.mock.ts +51 -51
  268. package/src/_modules/mock/app-params.mock.spec.ts +21 -21
  269. package/src/_modules/mock/app-params.mock.ts +9 -9
  270. package/src/_modules/mock/app-server.mock.ts +188 -188
  271. package/src/_modules/mock/auth-service.mock.spec.ts +47 -47
  272. package/src/_modules/mock/auth-service.mock.ts +28 -28
  273. package/src/_modules/mock/controller.mock.spec.ts +26 -26
  274. package/src/_modules/mock/controller.mock.ts +16 -16
  275. package/src/_modules/mock/data-model.mock.spec.ts +111 -111
  276. package/src/_modules/mock/data-model.mock.ts +82 -82
  277. package/src/_modules/mock/email-service-collection.mock.spec.ts +24 -24
  278. package/src/_modules/mock/email-service-collection.mock.ts +15 -15
  279. package/src/_modules/mock/email-service.mock.spec.ts +17 -17
  280. package/src/_modules/mock/email-service.mock.ts +20 -20
  281. package/src/_modules/mock/email-template.mock.html +14 -14
  282. package/src/_modules/mock/endpoint.mock.ts +91 -91
  283. package/src/_modules/mock/socket-client.mock.spec.ts +40 -40
  284. package/src/_modules/mock/socket-client.mock.ts +45 -45
  285. package/src/_modules/mock/socket-server.mock.spec.ts +44 -44
  286. package/src/_modules/mock/socket-server.mock.ts +46 -46
  287. package/src/_modules/oauth2/_routes/oauth2.controller.spec.ts +107 -107
  288. package/src/_modules/oauth2/_routes/oauth2.controller.ts +98 -98
  289. package/src/_modules/oauth2/_services/oauth2.auth-service.spec.ts +254 -254
  290. package/src/_modules/oauth2/_services/oauth2.auth-service.ts +232 -232
  291. package/src/_modules/oauth2/_services/oauth2.control-service.spec.ts +585 -585
  292. package/src/_modules/oauth2/_services/oauth2.control-service.ts +653 -653
  293. package/src/_modules/oauth2/index.ts +17 -17
  294. package/src/_modules/scheduler/_models/scheduler-job.interface.ts +35 -35
  295. package/src/_modules/scheduler/get-scheduler-routing-module.util.ts +33 -33
  296. package/src/_modules/scheduler/index.ts +8 -8
  297. package/src/_modules/scheduler/scheduler.controller.spec.ts +42 -42
  298. package/src/_modules/scheduler/scheduler.controller.ts +69 -69
  299. package/src/_modules/scheduler/scheduler.service.spec.ts +141 -141
  300. package/src/_modules/scheduler/scheduler.service.ts +176 -176
  301. package/src/_modules/scoped-config/_enums/dynts-scoped-config-level.enum.ts +22 -22
  302. package/src/_modules/scoped-config/_models/data-models/dynts-scoped-config.data-model.ts +81 -81
  303. package/src/_modules/scoped-config/_models/interfaces/dynts-scoped-config.interface.ts +107 -107
  304. package/src/_modules/scoped-config/_services/dynts-scoped-config.control-service.spec.ts +306 -306
  305. package/src/_modules/scoped-config/_services/dynts-scoped-config.control-service.ts +295 -295
  306. package/src/_modules/scoped-config/_services/dynts-scoped-config.data-service.spec.ts +118 -118
  307. package/src/_modules/scoped-config/_services/dynts-scoped-config.data-service.ts +105 -105
  308. package/src/_modules/scoped-config/index.ts +17 -17
  309. package/src/_modules/server/errors/errors.control-service.spec.ts +238 -238
  310. package/src/_modules/server/errors/errors.control-service.ts +100 -100
  311. package/src/_modules/server/errors/errors.controller.spec.ts +268 -268
  312. package/src/_modules/server/errors/errors.controller.ts +515 -515
  313. package/src/_modules/server/errors/errors.data-service.spec.ts +480 -480
  314. package/src/_modules/server/index.ts +30 -30
  315. package/src/_modules/server/server-status/server-status-snapshot.control-service.spec.ts +70 -70
  316. package/src/_modules/server/server-status/server-status-snapshot.control-service.ts +17 -17
  317. package/src/_modules/server/server-status/server-status-snapshot.data-service.spec.ts +77 -77
  318. package/src/_modules/server/server-status/server-status-snapshot.data-service.ts +37 -37
  319. package/src/_modules/server/server-status/server-status.control-service.spec.ts +576 -576
  320. package/src/_modules/server/server-status/server-status.control-service.ts +396 -396
  321. package/src/_modules/server/server-status/server-status.controller.spec.ts +255 -255
  322. package/src/_modules/server/server-status/server-status.controller.ts +272 -272
  323. package/src/_modules/socket/_enums/socket-security.enum.ts +11 -11
  324. package/src/_modules/socket/_models/socket-client-service-params.control-model.spec.ts +32 -32
  325. package/src/_modules/socket/_models/socket-client-service-params.control-model.ts +22 -22
  326. package/src/_modules/socket/_models/socket-presence.control-model.spec.ts +164 -164
  327. package/src/_modules/socket/_models/socket-presence.control-model.ts +210 -210
  328. package/src/_modules/socket/_models/socket-server-service-params.control-model.spec.ts +46 -46
  329. package/src/_modules/socket/_models/socket-server-service-params.control-model.ts +22 -22
  330. package/src/_modules/socket/_services/socket-client.service.spec.ts +15 -15
  331. package/src/_modules/socket/_services/socket-client.service.ts +260 -260
  332. package/src/_modules/socket/_services/socket-server.service.spec.ts +11 -11
  333. package/src/_modules/socket/app-extended.integration.spec.ts +85 -85
  334. package/src/_modules/socket/app-extended.server.ts +630 -630
  335. package/src/_modules/socket/index.ts +42 -42
  336. package/src/_modules/test/get-test-routing-module.util.spec.ts +28 -28
  337. package/src/_modules/test/get-test-routing-module.util.ts +23 -23
  338. package/src/_modules/test/index.ts +11 -11
  339. package/src/_modules/test/test.controller.spec.ts +72 -72
  340. package/src/_modules/test/test.controller.ts +115 -115
  341. package/src/_modules/usage/get-usage-routing-module.util.ts +22 -22
  342. package/src/_modules/usage/index.ts +15 -15
  343. package/src/_modules/usage/usage.controller.spec.ts +81 -81
  344. package/src/_modules/usage/usage.controller.ts +126 -126
  345. package/src/_modules/usage/usage.data-service.spec.ts +332 -332
  346. package/src/_modules/usage/usage.data-service.ts +185 -185
  347. package/src/_services/base/api.service-base.spec.ts +125 -125
  348. package/src/_services/base/api.service-base.ts +74 -74
  349. package/src/_services/base/archive-data.service.spec.ts +209 -209
  350. package/src/_services/base/archive-data.service.ts +224 -224
  351. package/src/_services/base/data.service.spec.ts +729 -729
  352. package/src/_services/base/data.service.ts +2744 -2740
  353. package/src/_services/base/db.service.spec.ts +160 -73
  354. package/src/_services/base/db.service.ts +1592 -1575
  355. package/src/_services/base/singleton.service-base.spec.ts +28 -28
  356. package/src/_services/base/singleton.service-base.ts +24 -24
  357. package/src/_services/base/singleton.service.spec.ts +114 -114
  358. package/src/_services/base/singleton.service.ts +38 -38
  359. package/src/_services/core/api.service.spec.ts +140 -140
  360. package/src/_services/core/auth.service.spec.ts +159 -159
  361. package/src/_services/core/auth.service.ts +174 -174
  362. package/src/_services/core/email.service.spec.ts +85 -85
  363. package/src/_services/core/email.service.ts +742 -742
  364. package/src/_services/core/global.service.spec.ts +292 -292
  365. package/src/_services/core/global.service.ts +487 -487
  366. package/src/_services/core/memory-guard.service.spec.ts +245 -245
  367. package/src/_services/core/memory-guard.service.ts +481 -481
  368. package/src/_services/core/service-collection.service.spec.ts +46 -46
  369. package/src/_services/core/service-collection.service.ts +6 -6
  370. package/src/_services/route/controller.service.spec.ts +53 -53
  371. package/src/_services/route/controller.service.ts +148 -148
  372. package/src/_services/route/routing-module.service.spec.ts +98 -98
  373. package/src/_services/route/routing-module.service.ts +330 -330
  374. package/src/_services/server/app.server.ts +1941 -1941
  375. package/src/_services/shared.static-service.spec.ts +99 -99
  376. package/src/_services/shared.static-service.ts +78 -78
  377. package/src/index.ts +100 -99
  378. package/tsconfig.app.json +12 -12
  379. package/tsconfig.json +42 -42
  380. package/.dynamo/logs/cicd-pipeline/output.log +0 -2889
  381. package/.dynamo/logs/cicd-pipeline/status.json +0 -74
@@ -1,480 +1,480 @@
1
-
2
- import { DyNTS_LVS_VectorDataService } from './lvs-local-vector-search.data-service';
3
- import { DyFM_DataModel_Params, DyFM_Metadata, DyFM_BasicProperty_Type, DyFM_EnvironmentFlag } from '@futdevpro/fsm-dynamo';
4
- import { DyFM_OAI_Settings, DyFM_OAI_Model } from '@futdevpro/fsm-dynamo/ai/open-ai';
5
- import { LVS_Search_Mode } from '../_enums/lvs-search-mode.enum';
6
- import { LVS_VectorPool_ControlService } from './lvs-vector-pool.control-service';
7
- import { DyFM_Error } from '@futdevpro/fsm-dynamo';
8
- import { DyNTS_global_settings } from '../../../_collections/global-settings.const';
9
- import { DyNTS_GlobalService } from '../../../_services/core/global.service';
10
-
11
- class TestDataModel extends DyFM_Metadata {
12
- content: string = '';
13
- contentVectorized?: number[];
14
- }
15
-
16
- const testDataParams: DyFM_DataModel_Params<TestDataModel> = new DyFM_DataModel_Params<TestDataModel>({
17
- dataName: 'test-data',
18
- properties: {
19
- content: { key: 'content', type: DyFM_BasicProperty_Type.string },
20
- contentVectorized: {
21
- key: 'contentVectorized',
22
- type: DyFM_BasicProperty_Type.array,
23
- vectorizedFrom: ['content'],
24
- embeddingModel: DyFM_OAI_Model.textEmbedding_3Small,
25
- },
26
- },
27
- });
28
-
29
- describe('| DyNTS_LVS_VectorDataService', () => {
30
- let service: DyNTS_LVS_VectorDataService<TestDataModel>;
31
- let mockOpenAISettings: DyFM_OAI_Settings;
32
- let testData: TestDataModel;
33
- let mockDBService: jasmine.SpyObj<{
34
- find: (f: unknown) => Promise<unknown[]>;
35
- getAll: () => Promise<unknown[]>;
36
- getDataById: (id: string) => Promise<unknown>;
37
- }>;
38
-
39
- beforeAll(() => {
40
- if (!DyNTS_global_settings.systemShortCodeName) {
41
- (DyNTS_global_settings as { systemShortCodeName?: string }).systemShortCodeName = 'TEST';
42
- }
43
- if (!DyNTS_global_settings.env_settings) {
44
- (DyNTS_global_settings as { env_settings?: unknown }).env_settings = {
45
- environment: DyFM_EnvironmentFlag.local,
46
- };
47
- }
48
- });
49
-
50
- beforeEach(() => {
51
- mockDBService = jasmine.createSpyObj('DyNTS_DBService', [
52
- 'find', 'findOne', 'getDataById', 'getAll', 'getDataListByIds', 'getDataByDependencyId',
53
- 'getDataListByDependencyId', 'getDataListByDependencyIds', 'createData', 'modifyData',
54
- 'updateOne', 'markDeletedById', 'trueDeleteDataById', 'trueDeleteAllData', 'restoreDeletedById', 'aggregate',
55
- ]);
56
- spyOn(DyNTS_GlobalService, 'getDBService').and.returnValue(mockDBService as never);
57
- spyOn(DyNTS_GlobalService, 'getDBServiceByKey').and.returnValue(mockDBService as never);
58
-
59
- mockOpenAISettings = {
60
- config: { apiKey: 'test-api-key', organization: 'test-org' },
61
- defaultSettings: { useModel: DyFM_OAI_Model.textEmbedding_3Small },
62
- };
63
-
64
- testData = new TestDataModel();
65
- service = new DyNTS_LVS_VectorDataService<TestDataModel>(
66
- testData,
67
- testDataParams,
68
- mockOpenAISettings,
69
- 'test-issuer'
70
- );
71
- });
72
-
73
- describe('| constructor', () => {
74
- it('| should initialize with default search mode', () => {
75
- expect(service.defaultSearchMode).toBe(LVS_Search_Mode.cosineSimilarity);
76
- });
77
-
78
- it('| should initialize with L2 normalization enabled', () => {
79
- expect(service.useL2Normalization).toBe(true);
80
- });
81
-
82
- it('| should initialize vector pool', () => {
83
- expect((service as any).vectorPool).toBeInstanceOf(LVS_VectorPool_ControlService);
84
- });
85
- });
86
-
87
- describe('| vectorSearch', () => {
88
- it('| should throw error when input is missing', async () => {
89
- try {
90
- await service.vectorSearch({
91
- input: '',
92
- searchInKey: 'contentVectorized',
93
- });
94
- fail('Should have thrown an error');
95
- } catch (err) {
96
- expect(err).toBeInstanceOf(DyFM_Error);
97
- expect((err as DyFM_Error)._errorCode).toContain('DyNTS-LVS-VS1');
98
- }
99
- });
100
-
101
- it('| should throw error when searchInKey property not found', async () => {
102
- try {
103
- await service.vectorSearch({
104
- input: 'test query',
105
- searchInKey: 'nonExistentKey',
106
- });
107
- fail('Should have thrown an error');
108
- } catch (err) {
109
- expect(err).toBeInstanceOf(DyFM_Error);
110
- expect((err as DyFM_Error)._errorCode).toContain('DyNTS-LVS-VS2');
111
- }
112
- });
113
-
114
- it('| should throw error when searchInKey is not vectorized', async () => {
115
- try {
116
- await service.vectorSearch({
117
- input: 'test query',
118
- searchInKey: 'content',
119
- });
120
- fail('Should have thrown an error');
121
- } catch (err) {
122
- expect(err).toBeInstanceOf(DyFM_Error);
123
- expect((err as DyFM_Error)._errorCode).toContain('DyNTS-LVS-VS3');
124
- }
125
- });
126
-
127
- it('| should return empty array when no data found', async () => {
128
- spyOn(service, 'getAll').and.returnValue(Promise.resolve([]));
129
-
130
- const result = await service.vectorSearch({
131
- input: 'test query',
132
- searchInKey: 'contentVectorized',
133
- });
134
-
135
- expect(result).toEqual([]);
136
- });
137
-
138
- it('| should perform vector search with filterBy', async () => {
139
- const mockData1: TestDataModel = new TestDataModel();
140
- mockData1._id = 'data-1';
141
- mockData1.content = 'Test content 1';
142
- mockData1.contentVectorized = [0.1, 0.2, 0.3];
143
-
144
- const mockData2: TestDataModel = new TestDataModel();
145
- mockData2._id = 'data-2';
146
- mockData2.content = 'Test content 2';
147
- mockData2.contentVectorized = [0.4, 0.5, 0.6];
148
-
149
- spyOn(service, 'findDataList').and.returnValue(Promise.resolve([mockData1, mockData2]));
150
- spyOn(service, 'vectorize').and.returnValue(Promise.resolve([0.1, 0.2, 0.3]));
151
-
152
- const result = await service.vectorSearch({
153
- input: 'test query',
154
- searchInKey: 'contentVectorized',
155
- filterBy: { content: 'Test' },
156
- limit: 2,
157
- });
158
-
159
- expect(service.findDataList).toHaveBeenCalled();
160
- expect(result).toBeDefined();
161
- });
162
-
163
- it('| should perform vector search without filterBy', async () => {
164
- const mockData: TestDataModel = new TestDataModel();
165
- mockData._id = 'data-1';
166
- mockData.content = 'Test content';
167
- mockData.contentVectorized = [0.1, 0.2, 0.3];
168
-
169
- spyOn(service, 'getAll').and.returnValue(Promise.resolve([mockData]));
170
- spyOn(service, 'vectorize').and.returnValue(Promise.resolve([0.1, 0.2, 0.3]));
171
-
172
- const result = await service.vectorSearch({
173
- input: 'test query',
174
- searchInKey: 'contentVectorized',
175
- limit: 1,
176
- });
177
-
178
- expect(service.getAll).toHaveBeenCalled();
179
- expect(result).toBeDefined();
180
- });
181
-
182
- it('| should use default limit of 3 when not provided', async () => {
183
- const mockData: TestDataModel = new TestDataModel();
184
- mockData._id = 'data-1';
185
- mockData.content = 'Test content';
186
- mockData.contentVectorized = [0.1, 0.2, 0.3];
187
-
188
- spyOn(service, 'getAll').and.returnValue(Promise.resolve([mockData]));
189
- spyOn(service, 'vectorize').and.returnValue(Promise.resolve([0.1, 0.2, 0.3]));
190
- spyOn((service as any).vectorPool, 'search').and.returnValue([
191
- { id: 'data-1', score: 0.9 },
192
- ]);
193
-
194
- await service.vectorSearch({
195
- input: 'test query',
196
- searchInKey: 'contentVectorized',
197
- });
198
-
199
- expect((service as any).vectorPool.search).toHaveBeenCalledWith(
200
- jasmine.any(Array),
201
- 3,
202
- LVS_Search_Mode.cosineSimilarity
203
- );
204
- });
205
-
206
- it('| should use custom search mode when provided', async () => {
207
- const mockData: TestDataModel = new TestDataModel();
208
- mockData._id = 'data-1';
209
- mockData.content = 'Test content';
210
- mockData.contentVectorized = [0.1, 0.2, 0.3];
211
-
212
- spyOn(service, 'getAll').and.returnValue(Promise.resolve([mockData]));
213
- spyOn(service, 'vectorize').and.returnValue(Promise.resolve([0.1, 0.2, 0.3]));
214
- spyOn((service as any).vectorPool, 'search').and.returnValue([
215
- { id: 'data-1', score: 0.5 },
216
- ]);
217
-
218
- await service.vectorSearch({
219
- input: 'test query',
220
- searchInKey: 'contentVectorized',
221
- searchMode: LVS_Search_Mode.l2Distance,
222
- });
223
-
224
- expect((service as any).vectorPool.search).toHaveBeenCalledWith(
225
- jasmine.any(Array),
226
- 3,
227
- LVS_Search_Mode.l2Distance
228
- );
229
- });
230
-
231
- it('| should skip items without _id', async () => {
232
- const mockData1: TestDataModel = new TestDataModel();
233
- mockData1._id = 'data-1';
234
- mockData1.content = 'Test content 1';
235
- mockData1.contentVectorized = [0.1, 0.2, 0.3];
236
-
237
- const mockData2: TestDataModel = new TestDataModel();
238
- // No _id
239
- mockData2.content = 'Test content 2';
240
- mockData2.contentVectorized = [0.4, 0.5, 0.6];
241
-
242
- spyOn(service, 'getAll').and.returnValue(Promise.resolve([mockData1, mockData2]));
243
- spyOn(service, 'vectorize').and.returnValue(Promise.resolve([0.1, 0.2, 0.3]));
244
- spyOn((service as any).vectorPool, 'addVector');
245
-
246
- await service.vectorSearch({
247
- input: 'test query',
248
- searchInKey: 'contentVectorized',
249
- });
250
-
251
- expect((service as any).vectorPool.addVector).toHaveBeenCalledTimes(1);
252
- expect((service as any).vectorPool.addVector).toHaveBeenCalledWith('data-1', [0.1, 0.2, 0.3]);
253
- });
254
-
255
- it('| should skip items without vectorized value', async () => {
256
- const mockData1: TestDataModel = new TestDataModel();
257
- mockData1._id = 'data-1';
258
- mockData1.content = 'Test content 1';
259
- mockData1.contentVectorized = [0.1, 0.2, 0.3];
260
-
261
- const mockData2: TestDataModel = new TestDataModel();
262
- mockData2._id = 'data-2';
263
- mockData2.content = 'Test content 2';
264
- // No contentVectorized
265
-
266
- spyOn(service, 'getAll').and.returnValue(Promise.resolve([mockData1, mockData2]));
267
- spyOn(service, 'vectorize').and.returnValue(Promise.resolve([0.1, 0.2, 0.3]));
268
- spyOn((service as any).vectorPool, 'addVector');
269
-
270
- await service.vectorSearch({
271
- input: 'test query',
272
- searchInKey: 'contentVectorized',
273
- });
274
-
275
- expect((service as any).vectorPool.addVector).toHaveBeenCalledTimes(1);
276
- expect((service as any).vectorPool.addVector).toHaveBeenCalledWith('data-1', [0.1, 0.2, 0.3]);
277
- });
278
-
279
- it('| should clear vector pool after search', async () => {
280
- const mockData: TestDataModel = new TestDataModel();
281
- mockData._id = 'data-1';
282
- mockData.content = 'Test content';
283
- mockData.contentVectorized = [0.1, 0.2, 0.3];
284
-
285
- spyOn(service, 'getAll').and.returnValue(Promise.resolve([mockData]));
286
- spyOn(service, 'vectorize').and.returnValue(Promise.resolve([0.1, 0.2, 0.3]));
287
- spyOn((service as any).vectorPool, 'clearPool');
288
- spyOn((service as any).vectorPool, 'search').and.returnValue([]);
289
-
290
- await service.vectorSearch({
291
- input: 'test query',
292
- searchInKey: 'contentVectorized',
293
- });
294
-
295
- expect((service as any).vectorPool.clearPool).toHaveBeenCalled();
296
- });
297
-
298
- it('| should clear vector pool on error', async () => {
299
- spyOn(service, 'getAll').and.returnValue(Promise.reject(new Error('Database error')));
300
- spyOn((service as any).vectorPool, 'clearPool');
301
-
302
- try {
303
- await service.vectorSearch({
304
- input: 'test query',
305
- searchInKey: 'contentVectorized',
306
- });
307
- fail('Should have thrown an error');
308
- } catch (err) {
309
- expect((service as any).vectorPool.clearPool).toHaveBeenCalled();
310
- expect(err).toBeInstanceOf(DyFM_Error);
311
- expect((err as DyFM_Error)._errorCode).toContain('DyNTS-LVS-VS0');
312
- }
313
- });
314
-
315
- it('| should map search results back to data objects', async () => {
316
- const mockData1: TestDataModel = new TestDataModel();
317
- mockData1._id = 'data-1';
318
- mockData1.content = 'Test content 1';
319
- mockData1.contentVectorized = [0.1, 0.2, 0.3];
320
-
321
- const mockData2: TestDataModel = new TestDataModel();
322
- mockData2._id = 'data-2';
323
- mockData2.content = 'Test content 2';
324
- mockData2.contentVectorized = [0.4, 0.5, 0.6];
325
-
326
- spyOn(service, 'getAll').and.returnValue(Promise.resolve([mockData1, mockData2]));
327
- spyOn(service, 'vectorize').and.returnValue(Promise.resolve([0.1, 0.2, 0.3]));
328
- spyOn((service as any).vectorPool, 'search').and.returnValue([
329
- { id: 'data-2', score: 0.9 },
330
- { id: 'data-1', score: 0.8 },
331
- ]);
332
-
333
- const result = await service.vectorSearch({
334
- input: 'test query',
335
- searchInKey: 'contentVectorized',
336
- limit: 2,
337
- });
338
-
339
- expect(result.length).toBe(2);
340
- expect(result[0]._id).toBe('data-2');
341
- expect(result[1]._id).toBe('data-1');
342
- });
343
- });
344
-
345
- describe('| vectorSearch hybrid (FR-004)', () => {
346
- const buildHybridCorpus = (): TestDataModel[] => {
347
- const d1: TestDataModel = new TestDataModel();
348
- d1._id = 'doc-user';
349
- d1.content = 'the UserController handles authentication flow';
350
- d1.contentVectorized = [0.4, 0.5, 0.6];
351
- const d2: TestDataModel = new TestDataModel();
352
- d2._id = 'doc-recipe';
353
- d2.content = 'cooking recipes for desserts and cakes';
354
- d2.contentVectorized = [0.45, 0.55, 0.65];
355
- const d3: TestDataModel = new TestDataModel();
356
- d3._id = 'doc-db';
357
- d3.content = 'database setup guide for MongoDB';
358
- d3.contentVectorized = [0.42, 0.52, 0.62];
359
- return [d1, d2, d3];
360
- };
361
-
362
- it('| throws ha textSearchKey hianyzik hybrid modban (VS4)', async () => {
363
- spyOn(service, 'getAll').and.returnValue(Promise.resolve(buildHybridCorpus()));
364
- spyOn(service, 'vectorize').and.returnValue(Promise.resolve([0.4, 0.5, 0.6]));
365
- try {
366
- await service.vectorSearch({
367
- input: 'UserController',
368
- searchInKey: 'contentVectorized',
369
- searchMode: LVS_Search_Mode.hybrid,
370
- });
371
- fail('Should have thrown an error');
372
- } catch (err) {
373
- expect(err).toBeInstanceOf(DyFM_Error);
374
- expect((err as DyFM_Error)._errorCode).toContain('DyNTS-LVS-VS4');
375
- }
376
- });
377
-
378
- it('| throws ha hybridWeight invalid (negativ) (VS5)', async () => {
379
- spyOn(service, 'getAll').and.returnValue(Promise.resolve(buildHybridCorpus()));
380
- spyOn(service, 'vectorize').and.returnValue(Promise.resolve([0.4, 0.5, 0.6]));
381
- try {
382
- await service.vectorSearch({
383
- input: 'UserController',
384
- searchInKey: 'contentVectorized',
385
- searchMode: LVS_Search_Mode.hybrid,
386
- textSearchKey: 'content',
387
- hybridWeight: { vector: -0.5, text: 1.5 },
388
- });
389
- fail('Should have thrown an error');
390
- } catch (err) {
391
- expect(err).toBeInstanceOf(DyFM_Error);
392
- expect((err as DyFM_Error)._errorCode).toContain('DyNTS-LVS-VS5');
393
- }
394
- });
395
-
396
- it('| basic hybrid: text-relevant doc top-en', async () => {
397
- spyOn(service, 'getAll').and.returnValue(Promise.resolve(buildHybridCorpus()));
398
- spyOn(service, 'vectorize').and.returnValue(Promise.resolve([0.4, 0.5, 0.6]));
399
- const result: TestDataModel[] = await service.vectorSearch({
400
- input: 'UserController',
401
- searchInKey: 'contentVectorized',
402
- searchMode: LVS_Search_Mode.hybrid,
403
- textSearchKey: 'content',
404
- limit: 3,
405
- });
406
- expect(result.length).toBe(3);
407
- expect(result[0]._id).toBe('doc-user');
408
- });
409
-
410
- it('| weight {vector:1, text:0} → effektivan pure cosine', async () => {
411
- spyOn(service, 'getAll').and.returnValue(Promise.resolve(buildHybridCorpus()));
412
- spyOn(service, 'vectorize').and.returnValue(Promise.resolve([0.42, 0.52, 0.62]));
413
- const result: TestDataModel[] = await service.vectorSearch({
414
- input: 'UserController',
415
- searchInKey: 'contentVectorized',
416
- searchMode: LVS_Search_Mode.hybrid,
417
- textSearchKey: 'content',
418
- hybridWeight: { vector: 1, text: 0 },
419
- limit: 3,
420
- });
421
- expect(result.length).toBe(3);
422
- expect(result[0]._id).toBe('doc-db');
423
- });
424
-
425
- it('| weight {vector:0, text:1} → effektivan pure BM25', async () => {
426
- spyOn(service, 'getAll').and.returnValue(Promise.resolve(buildHybridCorpus()));
427
- spyOn(service, 'vectorize').and.returnValue(Promise.resolve([0.45, 0.55, 0.65]));
428
- const result: TestDataModel[] = await service.vectorSearch({
429
- input: 'authentication',
430
- searchInKey: 'contentVectorized',
431
- searchMode: LVS_Search_Mode.hybrid,
432
- textSearchKey: 'content',
433
- hybridWeight: { vector: 0, text: 1 },
434
- limit: 3,
435
- });
436
- expect(result.length).toBe(3);
437
- expect(result[0]._id).toBe('doc-user');
438
- });
439
-
440
- it('| all-zero BM25 fallback → cosine-rendezes marad', async () => {
441
- spyOn(service, 'getAll').and.returnValue(Promise.resolve(buildHybridCorpus()));
442
- spyOn(service, 'vectorize').and.returnValue(Promise.resolve([0.45, 0.55, 0.65]));
443
- const result: TestDataModel[] = await service.vectorSearch({
444
- input: 'xyzzy-nonexistent-token',
445
- searchInKey: 'contentVectorized',
446
- searchMode: LVS_Search_Mode.hybrid,
447
- textSearchKey: 'content',
448
- limit: 3,
449
- });
450
- expect(result.length).toBe(3);
451
- expect(result[0]._id).toBe('doc-recipe');
452
- });
453
-
454
- it('| limit honored hybrid modban', async () => {
455
- spyOn(service, 'getAll').and.returnValue(Promise.resolve(buildHybridCorpus()));
456
- spyOn(service, 'vectorize').and.returnValue(Promise.resolve([0.4, 0.5, 0.6]));
457
- const result: TestDataModel[] = await service.vectorSearch({
458
- input: 'UserController',
459
- searchInKey: 'contentVectorized',
460
- searchMode: LVS_Search_Mode.hybrid,
461
- textSearchKey: 'content',
462
- limit: 1,
463
- });
464
- expect(result.length).toBe(1);
465
- });
466
-
467
- it('| ures candidate-szet → ures eredmeny', async () => {
468
- spyOn(service, 'getAll').and.returnValue(Promise.resolve([]));
469
- spyOn(service, 'vectorize').and.returnValue(Promise.resolve([0.4, 0.5, 0.6]));
470
- const result: TestDataModel[] = await service.vectorSearch({
471
- input: 'UserController',
472
- searchInKey: 'contentVectorized',
473
- searchMode: LVS_Search_Mode.hybrid,
474
- textSearchKey: 'content',
475
- });
476
- expect(result.length).toBe(0);
477
- });
478
- });
479
- });
480
-
1
+
2
+ import { DyNTS_LVS_VectorDataService } from './lvs-local-vector-search.data-service';
3
+ import { DyFM_DataModel_Params, DyFM_Metadata, DyFM_BasicProperty_Type, DyFM_EnvironmentFlag } from '@futdevpro/fsm-dynamo';
4
+ import { DyFM_OAI_Settings, DyFM_OAI_Model } from '@futdevpro/fsm-dynamo/ai/open-ai';
5
+ import { LVS_Search_Mode } from '../_enums/lvs-search-mode.enum';
6
+ import { LVS_VectorPool_ControlService } from './lvs-vector-pool.control-service';
7
+ import { DyFM_Error } from '@futdevpro/fsm-dynamo';
8
+ import { DyNTS_global_settings } from '../../../_collections/global-settings.const';
9
+ import { DyNTS_GlobalService } from '../../../_services/core/global.service';
10
+
11
+ class TestDataModel extends DyFM_Metadata {
12
+ content: string = '';
13
+ contentVectorized?: number[];
14
+ }
15
+
16
+ const testDataParams: DyFM_DataModel_Params<TestDataModel> = new DyFM_DataModel_Params<TestDataModel>({
17
+ dataName: 'test-data',
18
+ properties: {
19
+ content: { key: 'content', type: DyFM_BasicProperty_Type.string },
20
+ contentVectorized: {
21
+ key: 'contentVectorized',
22
+ type: DyFM_BasicProperty_Type.array,
23
+ vectorizedFrom: ['content'],
24
+ embeddingModel: DyFM_OAI_Model.textEmbedding_3Small,
25
+ },
26
+ },
27
+ });
28
+
29
+ describe('| DyNTS_LVS_VectorDataService', () => {
30
+ let service: DyNTS_LVS_VectorDataService<TestDataModel>;
31
+ let mockOpenAISettings: DyFM_OAI_Settings;
32
+ let testData: TestDataModel;
33
+ let mockDBService: jasmine.SpyObj<{
34
+ find: (f: unknown) => Promise<unknown[]>;
35
+ getAll: () => Promise<unknown[]>;
36
+ getDataById: (id: string) => Promise<unknown>;
37
+ }>;
38
+
39
+ beforeAll(() => {
40
+ if (!DyNTS_global_settings.systemShortCodeName) {
41
+ (DyNTS_global_settings as { systemShortCodeName?: string }).systemShortCodeName = 'TEST';
42
+ }
43
+ if (!DyNTS_global_settings.env_settings) {
44
+ (DyNTS_global_settings as { env_settings?: unknown }).env_settings = {
45
+ environment: DyFM_EnvironmentFlag.local,
46
+ };
47
+ }
48
+ });
49
+
50
+ beforeEach(() => {
51
+ mockDBService = jasmine.createSpyObj('DyNTS_DBService', [
52
+ 'find', 'findOne', 'getDataById', 'getAll', 'getDataListByIds', 'getDataByDependencyId',
53
+ 'getDataListByDependencyId', 'getDataListByDependencyIds', 'createData', 'modifyData',
54
+ 'updateOne', 'markDeletedById', 'trueDeleteDataById', 'trueDeleteAllData', 'restoreDeletedById', 'aggregate',
55
+ ]);
56
+ spyOn(DyNTS_GlobalService, 'getDBService').and.returnValue(mockDBService as never);
57
+ spyOn(DyNTS_GlobalService, 'getDBServiceByKey').and.returnValue(mockDBService as never);
58
+
59
+ mockOpenAISettings = {
60
+ config: { apiKey: 'test-api-key', organization: 'test-org' },
61
+ defaultSettings: { useModel: DyFM_OAI_Model.textEmbedding_3Small },
62
+ };
63
+
64
+ testData = new TestDataModel();
65
+ service = new DyNTS_LVS_VectorDataService<TestDataModel>(
66
+ testData,
67
+ testDataParams,
68
+ mockOpenAISettings,
69
+ 'test-issuer'
70
+ );
71
+ });
72
+
73
+ describe('| constructor', () => {
74
+ it('| should initialize with default search mode', () => {
75
+ expect(service.defaultSearchMode).toBe(LVS_Search_Mode.cosineSimilarity);
76
+ });
77
+
78
+ it('| should initialize with L2 normalization enabled', () => {
79
+ expect(service.useL2Normalization).toBe(true);
80
+ });
81
+
82
+ it('| should initialize vector pool', () => {
83
+ expect((service as any).vectorPool).toBeInstanceOf(LVS_VectorPool_ControlService);
84
+ });
85
+ });
86
+
87
+ describe('| vectorSearch', () => {
88
+ it('| should throw error when input is missing', async () => {
89
+ try {
90
+ await service.vectorSearch({
91
+ input: '',
92
+ searchInKey: 'contentVectorized',
93
+ });
94
+ fail('Should have thrown an error');
95
+ } catch (err) {
96
+ expect(err).toBeInstanceOf(DyFM_Error);
97
+ expect((err as DyFM_Error)._errorCode).toContain('DyNTS-LVS-VS1');
98
+ }
99
+ });
100
+
101
+ it('| should throw error when searchInKey property not found', async () => {
102
+ try {
103
+ await service.vectorSearch({
104
+ input: 'test query',
105
+ searchInKey: 'nonExistentKey',
106
+ });
107
+ fail('Should have thrown an error');
108
+ } catch (err) {
109
+ expect(err).toBeInstanceOf(DyFM_Error);
110
+ expect((err as DyFM_Error)._errorCode).toContain('DyNTS-LVS-VS2');
111
+ }
112
+ });
113
+
114
+ it('| should throw error when searchInKey is not vectorized', async () => {
115
+ try {
116
+ await service.vectorSearch({
117
+ input: 'test query',
118
+ searchInKey: 'content',
119
+ });
120
+ fail('Should have thrown an error');
121
+ } catch (err) {
122
+ expect(err).toBeInstanceOf(DyFM_Error);
123
+ expect((err as DyFM_Error)._errorCode).toContain('DyNTS-LVS-VS3');
124
+ }
125
+ });
126
+
127
+ it('| should return empty array when no data found', async () => {
128
+ spyOn(service, 'getAll').and.returnValue(Promise.resolve([]));
129
+
130
+ const result = await service.vectorSearch({
131
+ input: 'test query',
132
+ searchInKey: 'contentVectorized',
133
+ });
134
+
135
+ expect(result).toEqual([]);
136
+ });
137
+
138
+ it('| should perform vector search with filterBy', async () => {
139
+ const mockData1: TestDataModel = new TestDataModel();
140
+ mockData1._id = 'data-1';
141
+ mockData1.content = 'Test content 1';
142
+ mockData1.contentVectorized = [0.1, 0.2, 0.3];
143
+
144
+ const mockData2: TestDataModel = new TestDataModel();
145
+ mockData2._id = 'data-2';
146
+ mockData2.content = 'Test content 2';
147
+ mockData2.contentVectorized = [0.4, 0.5, 0.6];
148
+
149
+ spyOn(service, 'findDataList').and.returnValue(Promise.resolve([mockData1, mockData2]));
150
+ spyOn(service, 'vectorize').and.returnValue(Promise.resolve([0.1, 0.2, 0.3]));
151
+
152
+ const result = await service.vectorSearch({
153
+ input: 'test query',
154
+ searchInKey: 'contentVectorized',
155
+ filterBy: { content: 'Test' },
156
+ limit: 2,
157
+ });
158
+
159
+ expect(service.findDataList).toHaveBeenCalled();
160
+ expect(result).toBeDefined();
161
+ });
162
+
163
+ it('| should perform vector search without filterBy', async () => {
164
+ const mockData: TestDataModel = new TestDataModel();
165
+ mockData._id = 'data-1';
166
+ mockData.content = 'Test content';
167
+ mockData.contentVectorized = [0.1, 0.2, 0.3];
168
+
169
+ spyOn(service, 'getAll').and.returnValue(Promise.resolve([mockData]));
170
+ spyOn(service, 'vectorize').and.returnValue(Promise.resolve([0.1, 0.2, 0.3]));
171
+
172
+ const result = await service.vectorSearch({
173
+ input: 'test query',
174
+ searchInKey: 'contentVectorized',
175
+ limit: 1,
176
+ });
177
+
178
+ expect(service.getAll).toHaveBeenCalled();
179
+ expect(result).toBeDefined();
180
+ });
181
+
182
+ it('| should use default limit of 3 when not provided', async () => {
183
+ const mockData: TestDataModel = new TestDataModel();
184
+ mockData._id = 'data-1';
185
+ mockData.content = 'Test content';
186
+ mockData.contentVectorized = [0.1, 0.2, 0.3];
187
+
188
+ spyOn(service, 'getAll').and.returnValue(Promise.resolve([mockData]));
189
+ spyOn(service, 'vectorize').and.returnValue(Promise.resolve([0.1, 0.2, 0.3]));
190
+ spyOn((service as any).vectorPool, 'search').and.returnValue([
191
+ { id: 'data-1', score: 0.9 },
192
+ ]);
193
+
194
+ await service.vectorSearch({
195
+ input: 'test query',
196
+ searchInKey: 'contentVectorized',
197
+ });
198
+
199
+ expect((service as any).vectorPool.search).toHaveBeenCalledWith(
200
+ jasmine.any(Array),
201
+ 3,
202
+ LVS_Search_Mode.cosineSimilarity
203
+ );
204
+ });
205
+
206
+ it('| should use custom search mode when provided', async () => {
207
+ const mockData: TestDataModel = new TestDataModel();
208
+ mockData._id = 'data-1';
209
+ mockData.content = 'Test content';
210
+ mockData.contentVectorized = [0.1, 0.2, 0.3];
211
+
212
+ spyOn(service, 'getAll').and.returnValue(Promise.resolve([mockData]));
213
+ spyOn(service, 'vectorize').and.returnValue(Promise.resolve([0.1, 0.2, 0.3]));
214
+ spyOn((service as any).vectorPool, 'search').and.returnValue([
215
+ { id: 'data-1', score: 0.5 },
216
+ ]);
217
+
218
+ await service.vectorSearch({
219
+ input: 'test query',
220
+ searchInKey: 'contentVectorized',
221
+ searchMode: LVS_Search_Mode.l2Distance,
222
+ });
223
+
224
+ expect((service as any).vectorPool.search).toHaveBeenCalledWith(
225
+ jasmine.any(Array),
226
+ 3,
227
+ LVS_Search_Mode.l2Distance
228
+ );
229
+ });
230
+
231
+ it('| should skip items without _id', async () => {
232
+ const mockData1: TestDataModel = new TestDataModel();
233
+ mockData1._id = 'data-1';
234
+ mockData1.content = 'Test content 1';
235
+ mockData1.contentVectorized = [0.1, 0.2, 0.3];
236
+
237
+ const mockData2: TestDataModel = new TestDataModel();
238
+ // No _id
239
+ mockData2.content = 'Test content 2';
240
+ mockData2.contentVectorized = [0.4, 0.5, 0.6];
241
+
242
+ spyOn(service, 'getAll').and.returnValue(Promise.resolve([mockData1, mockData2]));
243
+ spyOn(service, 'vectorize').and.returnValue(Promise.resolve([0.1, 0.2, 0.3]));
244
+ spyOn((service as any).vectorPool, 'addVector');
245
+
246
+ await service.vectorSearch({
247
+ input: 'test query',
248
+ searchInKey: 'contentVectorized',
249
+ });
250
+
251
+ expect((service as any).vectorPool.addVector).toHaveBeenCalledTimes(1);
252
+ expect((service as any).vectorPool.addVector).toHaveBeenCalledWith('data-1', [0.1, 0.2, 0.3]);
253
+ });
254
+
255
+ it('| should skip items without vectorized value', async () => {
256
+ const mockData1: TestDataModel = new TestDataModel();
257
+ mockData1._id = 'data-1';
258
+ mockData1.content = 'Test content 1';
259
+ mockData1.contentVectorized = [0.1, 0.2, 0.3];
260
+
261
+ const mockData2: TestDataModel = new TestDataModel();
262
+ mockData2._id = 'data-2';
263
+ mockData2.content = 'Test content 2';
264
+ // No contentVectorized
265
+
266
+ spyOn(service, 'getAll').and.returnValue(Promise.resolve([mockData1, mockData2]));
267
+ spyOn(service, 'vectorize').and.returnValue(Promise.resolve([0.1, 0.2, 0.3]));
268
+ spyOn((service as any).vectorPool, 'addVector');
269
+
270
+ await service.vectorSearch({
271
+ input: 'test query',
272
+ searchInKey: 'contentVectorized',
273
+ });
274
+
275
+ expect((service as any).vectorPool.addVector).toHaveBeenCalledTimes(1);
276
+ expect((service as any).vectorPool.addVector).toHaveBeenCalledWith('data-1', [0.1, 0.2, 0.3]);
277
+ });
278
+
279
+ it('| should clear vector pool after search', async () => {
280
+ const mockData: TestDataModel = new TestDataModel();
281
+ mockData._id = 'data-1';
282
+ mockData.content = 'Test content';
283
+ mockData.contentVectorized = [0.1, 0.2, 0.3];
284
+
285
+ spyOn(service, 'getAll').and.returnValue(Promise.resolve([mockData]));
286
+ spyOn(service, 'vectorize').and.returnValue(Promise.resolve([0.1, 0.2, 0.3]));
287
+ spyOn((service as any).vectorPool, 'clearPool');
288
+ spyOn((service as any).vectorPool, 'search').and.returnValue([]);
289
+
290
+ await service.vectorSearch({
291
+ input: 'test query',
292
+ searchInKey: 'contentVectorized',
293
+ });
294
+
295
+ expect((service as any).vectorPool.clearPool).toHaveBeenCalled();
296
+ });
297
+
298
+ it('| should clear vector pool on error', async () => {
299
+ spyOn(service, 'getAll').and.returnValue(Promise.reject(new Error('Database error')));
300
+ spyOn((service as any).vectorPool, 'clearPool');
301
+
302
+ try {
303
+ await service.vectorSearch({
304
+ input: 'test query',
305
+ searchInKey: 'contentVectorized',
306
+ });
307
+ fail('Should have thrown an error');
308
+ } catch (err) {
309
+ expect((service as any).vectorPool.clearPool).toHaveBeenCalled();
310
+ expect(err).toBeInstanceOf(DyFM_Error);
311
+ expect((err as DyFM_Error)._errorCode).toContain('DyNTS-LVS-VS0');
312
+ }
313
+ });
314
+
315
+ it('| should map search results back to data objects', async () => {
316
+ const mockData1: TestDataModel = new TestDataModel();
317
+ mockData1._id = 'data-1';
318
+ mockData1.content = 'Test content 1';
319
+ mockData1.contentVectorized = [0.1, 0.2, 0.3];
320
+
321
+ const mockData2: TestDataModel = new TestDataModel();
322
+ mockData2._id = 'data-2';
323
+ mockData2.content = 'Test content 2';
324
+ mockData2.contentVectorized = [0.4, 0.5, 0.6];
325
+
326
+ spyOn(service, 'getAll').and.returnValue(Promise.resolve([mockData1, mockData2]));
327
+ spyOn(service, 'vectorize').and.returnValue(Promise.resolve([0.1, 0.2, 0.3]));
328
+ spyOn((service as any).vectorPool, 'search').and.returnValue([
329
+ { id: 'data-2', score: 0.9 },
330
+ { id: 'data-1', score: 0.8 },
331
+ ]);
332
+
333
+ const result = await service.vectorSearch({
334
+ input: 'test query',
335
+ searchInKey: 'contentVectorized',
336
+ limit: 2,
337
+ });
338
+
339
+ expect(result.length).toBe(2);
340
+ expect(result[0]._id).toBe('data-2');
341
+ expect(result[1]._id).toBe('data-1');
342
+ });
343
+ });
344
+
345
+ describe('| vectorSearch hybrid (FR-004)', () => {
346
+ const buildHybridCorpus = (): TestDataModel[] => {
347
+ const d1: TestDataModel = new TestDataModel();
348
+ d1._id = 'doc-user';
349
+ d1.content = 'the UserController handles authentication flow';
350
+ d1.contentVectorized = [0.4, 0.5, 0.6];
351
+ const d2: TestDataModel = new TestDataModel();
352
+ d2._id = 'doc-recipe';
353
+ d2.content = 'cooking recipes for desserts and cakes';
354
+ d2.contentVectorized = [0.45, 0.55, 0.65];
355
+ const d3: TestDataModel = new TestDataModel();
356
+ d3._id = 'doc-db';
357
+ d3.content = 'database setup guide for MongoDB';
358
+ d3.contentVectorized = [0.42, 0.52, 0.62];
359
+ return [d1, d2, d3];
360
+ };
361
+
362
+ it('| throws ha textSearchKey hianyzik hybrid modban (VS4)', async () => {
363
+ spyOn(service, 'getAll').and.returnValue(Promise.resolve(buildHybridCorpus()));
364
+ spyOn(service, 'vectorize').and.returnValue(Promise.resolve([0.4, 0.5, 0.6]));
365
+ try {
366
+ await service.vectorSearch({
367
+ input: 'UserController',
368
+ searchInKey: 'contentVectorized',
369
+ searchMode: LVS_Search_Mode.hybrid,
370
+ });
371
+ fail('Should have thrown an error');
372
+ } catch (err) {
373
+ expect(err).toBeInstanceOf(DyFM_Error);
374
+ expect((err as DyFM_Error)._errorCode).toContain('DyNTS-LVS-VS4');
375
+ }
376
+ });
377
+
378
+ it('| throws ha hybridWeight invalid (negativ) (VS5)', async () => {
379
+ spyOn(service, 'getAll').and.returnValue(Promise.resolve(buildHybridCorpus()));
380
+ spyOn(service, 'vectorize').and.returnValue(Promise.resolve([0.4, 0.5, 0.6]));
381
+ try {
382
+ await service.vectorSearch({
383
+ input: 'UserController',
384
+ searchInKey: 'contentVectorized',
385
+ searchMode: LVS_Search_Mode.hybrid,
386
+ textSearchKey: 'content',
387
+ hybridWeight: { vector: -0.5, text: 1.5 },
388
+ });
389
+ fail('Should have thrown an error');
390
+ } catch (err) {
391
+ expect(err).toBeInstanceOf(DyFM_Error);
392
+ expect((err as DyFM_Error)._errorCode).toContain('DyNTS-LVS-VS5');
393
+ }
394
+ });
395
+
396
+ it('| basic hybrid: text-relevant doc top-en', async () => {
397
+ spyOn(service, 'getAll').and.returnValue(Promise.resolve(buildHybridCorpus()));
398
+ spyOn(service, 'vectorize').and.returnValue(Promise.resolve([0.4, 0.5, 0.6]));
399
+ const result: TestDataModel[] = await service.vectorSearch({
400
+ input: 'UserController',
401
+ searchInKey: 'contentVectorized',
402
+ searchMode: LVS_Search_Mode.hybrid,
403
+ textSearchKey: 'content',
404
+ limit: 3,
405
+ });
406
+ expect(result.length).toBe(3);
407
+ expect(result[0]._id).toBe('doc-user');
408
+ });
409
+
410
+ it('| weight {vector:1, text:0} → effektivan pure cosine', async () => {
411
+ spyOn(service, 'getAll').and.returnValue(Promise.resolve(buildHybridCorpus()));
412
+ spyOn(service, 'vectorize').and.returnValue(Promise.resolve([0.42, 0.52, 0.62]));
413
+ const result: TestDataModel[] = await service.vectorSearch({
414
+ input: 'UserController',
415
+ searchInKey: 'contentVectorized',
416
+ searchMode: LVS_Search_Mode.hybrid,
417
+ textSearchKey: 'content',
418
+ hybridWeight: { vector: 1, text: 0 },
419
+ limit: 3,
420
+ });
421
+ expect(result.length).toBe(3);
422
+ expect(result[0]._id).toBe('doc-db');
423
+ });
424
+
425
+ it('| weight {vector:0, text:1} → effektivan pure BM25', async () => {
426
+ spyOn(service, 'getAll').and.returnValue(Promise.resolve(buildHybridCorpus()));
427
+ spyOn(service, 'vectorize').and.returnValue(Promise.resolve([0.45, 0.55, 0.65]));
428
+ const result: TestDataModel[] = await service.vectorSearch({
429
+ input: 'authentication',
430
+ searchInKey: 'contentVectorized',
431
+ searchMode: LVS_Search_Mode.hybrid,
432
+ textSearchKey: 'content',
433
+ hybridWeight: { vector: 0, text: 1 },
434
+ limit: 3,
435
+ });
436
+ expect(result.length).toBe(3);
437
+ expect(result[0]._id).toBe('doc-user');
438
+ });
439
+
440
+ it('| all-zero BM25 fallback → cosine-rendezes marad', async () => {
441
+ spyOn(service, 'getAll').and.returnValue(Promise.resolve(buildHybridCorpus()));
442
+ spyOn(service, 'vectorize').and.returnValue(Promise.resolve([0.45, 0.55, 0.65]));
443
+ const result: TestDataModel[] = await service.vectorSearch({
444
+ input: 'xyzzy-nonexistent-token',
445
+ searchInKey: 'contentVectorized',
446
+ searchMode: LVS_Search_Mode.hybrid,
447
+ textSearchKey: 'content',
448
+ limit: 3,
449
+ });
450
+ expect(result.length).toBe(3);
451
+ expect(result[0]._id).toBe('doc-recipe');
452
+ });
453
+
454
+ it('| limit honored hybrid modban', async () => {
455
+ spyOn(service, 'getAll').and.returnValue(Promise.resolve(buildHybridCorpus()));
456
+ spyOn(service, 'vectorize').and.returnValue(Promise.resolve([0.4, 0.5, 0.6]));
457
+ const result: TestDataModel[] = await service.vectorSearch({
458
+ input: 'UserController',
459
+ searchInKey: 'contentVectorized',
460
+ searchMode: LVS_Search_Mode.hybrid,
461
+ textSearchKey: 'content',
462
+ limit: 1,
463
+ });
464
+ expect(result.length).toBe(1);
465
+ });
466
+
467
+ it('| ures candidate-szet → ures eredmeny', async () => {
468
+ spyOn(service, 'getAll').and.returnValue(Promise.resolve([]));
469
+ spyOn(service, 'vectorize').and.returnValue(Promise.resolve([0.4, 0.5, 0.6]));
470
+ const result: TestDataModel[] = await service.vectorSearch({
471
+ input: 'UserController',
472
+ searchInKey: 'contentVectorized',
473
+ searchMode: LVS_Search_Mode.hybrid,
474
+ textSearchKey: 'content',
475
+ });
476
+ expect(result.length).toBe(0);
477
+ });
478
+ });
479
+ });
480
+