@lenne.tech/nest-server 12.0.0 → 12.1.0

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 (693) hide show
  1. package/.claude/rules/architecture.md +6 -1
  2. package/.claude/rules/better-auth.md +46 -0
  3. package/.claude/rules/configurable-features.md +3 -2
  4. package/.claude/rules/package-management.md +24 -2
  5. package/.claude/rules/persistence.md +100 -0
  6. package/.claude/rules/role-system.md +9 -0
  7. package/.claude/rules/testing.md +116 -18
  8. package/CLAUDE.md +21 -2
  9. package/FRAMEWORK-API.md +6 -4
  10. package/README.md +106 -34
  11. package/dist/core/common/decorators/unified-field.decorator.d.ts +2 -1
  12. package/dist/core/common/decorators/unified-field.decorator.js +4 -1
  13. package/dist/core/common/decorators/unified-field.decorator.js.map +1 -1
  14. package/dist/core/common/filters/mongoose-cast-error.filter.d.ts +7 -5
  15. package/dist/core/common/filters/mongoose-cast-error.filter.js +3 -2
  16. package/dist/core/common/filters/mongoose-cast-error.filter.js.map +1 -1
  17. package/dist/core/common/helpers/db.helper.d.ts +2 -1
  18. package/dist/core/common/helpers/db.helper.js +32 -26
  19. package/dist/core/common/helpers/db.helper.js.map +1 -1
  20. package/dist/core/common/helpers/decorator.helper.d.ts +1 -1
  21. package/dist/core/common/helpers/filter.helper.d.ts +2 -1
  22. package/dist/core/common/helpers/filter.helper.js.map +1 -1
  23. package/dist/core/common/helpers/gridfs.helper.d.ts +4 -4
  24. package/dist/core/common/helpers/gridfs.helper.js +14 -6
  25. package/dist/core/common/helpers/gridfs.helper.js.map +1 -1
  26. package/dist/core/common/helpers/id.helper.d.ts +4 -1
  27. package/dist/core/common/helpers/id.helper.js +10 -4
  28. package/dist/core/common/helpers/id.helper.js.map +1 -1
  29. package/dist/core/common/helpers/model.helper.js +5 -5
  30. package/dist/core/common/helpers/model.helper.js.map +1 -1
  31. package/dist/core/common/helpers/service.helper.js +3 -3
  32. package/dist/core/common/helpers/service.helper.js.map +1 -1
  33. package/dist/core/common/interfaces/server-options.interface.d.ts +18 -2
  34. package/dist/core/common/interfaces/service-options.interface.d.ts +2 -2
  35. package/dist/core/common/models/core-persistence.model.d.ts +1 -2
  36. package/dist/core/common/models/core-persistence.model.js +3 -3
  37. package/dist/core/common/models/core-persistence.model.js.map +1 -1
  38. package/dist/core/common/persistence/core-persistence.lifecycle.d.ts +9 -0
  39. package/dist/core/common/persistence/core-persistence.lifecycle.js +38 -0
  40. package/dist/core/common/persistence/core-persistence.lifecycle.js.map +1 -0
  41. package/dist/core/common/persistence/core-persistence.module.d.ts +9 -0
  42. package/dist/core/common/persistence/core-persistence.module.js +76 -0
  43. package/dist/core/common/persistence/core-persistence.module.js.map +1 -0
  44. package/dist/core/common/persistence/data-source.config.d.ts +33 -0
  45. package/dist/core/common/persistence/data-source.config.js +151 -0
  46. package/dist/core/common/persistence/data-source.config.js.map +1 -0
  47. package/dist/core/common/persistence/data-source.runtime.d.ts +45 -0
  48. package/dist/core/common/persistence/data-source.runtime.js +278 -0
  49. package/dist/core/common/persistence/data-source.runtime.js.map +1 -0
  50. package/dist/core/common/persistence/data-store.interface.d.ts +73 -0
  51. package/dist/core/common/persistence/data-store.interface.js +2 -0
  52. package/dist/core/common/persistence/data-store.interface.js.map +1 -0
  53. package/dist/core/common/persistence/expiry-sweep.d.ts +12 -0
  54. package/dist/core/common/persistence/expiry-sweep.js +55 -0
  55. package/dist/core/common/persistence/expiry-sweep.js.map +1 -0
  56. package/dist/core/common/persistence/id-format.d.ts +3 -0
  57. package/dist/core/common/persistence/id-format.js +21 -0
  58. package/dist/core/common/persistence/id-format.js.map +1 -0
  59. package/dist/core/common/persistence/infrastructure-locks.d.ts +13 -0
  60. package/dist/core/common/persistence/infrastructure-locks.js +35 -0
  61. package/dist/core/common/persistence/infrastructure-locks.js.map +1 -0
  62. package/dist/core/common/persistence/inject-store.decorator.d.ts +1 -0
  63. package/dist/core/common/persistence/inject-store.decorator.js +6 -0
  64. package/dist/core/common/persistence/inject-store.decorator.js.map +1 -0
  65. package/dist/core/common/persistence/lock-store.interface.d.ts +5 -0
  66. package/dist/core/common/persistence/lock-store.interface.js +2 -0
  67. package/dist/core/common/persistence/lock-store.interface.js.map +1 -0
  68. package/dist/core/common/persistence/model-descriptor.interface.d.ts +36 -0
  69. package/dist/core/common/persistence/model-descriptor.interface.js +2 -0
  70. package/dist/core/common/persistence/model-descriptor.interface.js.map +1 -0
  71. package/dist/core/common/persistence/model-metadata.registry.d.ts +14 -0
  72. package/dist/core/common/persistence/model-metadata.registry.js +194 -0
  73. package/dist/core/common/persistence/model-metadata.registry.js.map +1 -0
  74. package/dist/core/common/persistence/mongo/collection-name.d.ts +2 -0
  75. package/dist/core/common/persistence/mongo/collection-name.js +73 -0
  76. package/dist/core/common/persistence/mongo/collection-name.js.map +1 -0
  77. package/dist/core/common/persistence/mongo/declared-schema.view.d.ts +11 -0
  78. package/dist/core/common/persistence/mongo/declared-schema.view.js +292 -0
  79. package/dist/core/common/persistence/mongo/declared-schema.view.js.map +1 -0
  80. package/dist/core/common/persistence/mongo/hex-object-id.d.ts +13 -0
  81. package/dist/core/common/persistence/mongo/hex-object-id.js +54 -0
  82. package/dist/core/common/persistence/mongo/hex-object-id.js.map +1 -0
  83. package/dist/core/common/persistence/mongo/model-declarations.d.ts +35 -0
  84. package/dist/core/common/persistence/mongo/model-declarations.js +80 -0
  85. package/dist/core/common/persistence/mongo/model-declarations.js.map +1 -0
  86. package/dist/core/common/persistence/mongo/mongo-packages.d.ts +15 -0
  87. package/dist/core/common/persistence/mongo/mongo-packages.js +66 -0
  88. package/dist/core/common/persistence/mongo/mongo-packages.js.map +1 -0
  89. package/dist/core/common/persistence/mongo/mongoose-compat.d.ts +22 -0
  90. package/dist/core/common/persistence/mongo/mongoose-compat.js +65 -0
  91. package/dist/core/common/persistence/mongo/mongoose-compat.js.map +1 -0
  92. package/dist/core/common/persistence/mongo/no-mongo-connection.module.d.ts +2 -0
  93. package/dist/core/common/persistence/mongo/no-mongo-connection.module.js +19 -0
  94. package/dist/core/common/persistence/mongo/no-mongo-connection.module.js.map +1 -0
  95. package/dist/core/common/persistence/mongo-lock-store.d.ts +21 -0
  96. package/dist/core/common/persistence/mongo-lock-store.js +72 -0
  97. package/dist/core/common/persistence/mongo-lock-store.js.map +1 -0
  98. package/dist/core/common/persistence/mongoose-data-store.d.ts +33 -0
  99. package/dist/core/common/persistence/mongoose-data-store.js +187 -0
  100. package/dist/core/common/persistence/mongoose-data-store.js.map +1 -0
  101. package/dist/core/common/persistence/neutral-populate.d.ts +6 -0
  102. package/dist/core/common/persistence/neutral-populate.js +72 -0
  103. package/dist/core/common/persistence/neutral-populate.js.map +1 -0
  104. package/dist/core/common/persistence/persisted-model.decorator.d.ts +6 -0
  105. package/dist/core/common/persistence/persisted-model.decorator.js +24 -0
  106. package/dist/core/common/persistence/persisted-model.decorator.js.map +1 -0
  107. package/dist/core/common/persistence/persistence-runtime.registry.d.ts +61 -0
  108. package/dist/core/common/persistence/persistence-runtime.registry.js +47 -0
  109. package/dist/core/common/persistence/persistence-runtime.registry.js.map +1 -0
  110. package/dist/core/common/persistence/persistence.tokens.d.ts +1 -0
  111. package/dist/core/common/persistence/persistence.tokens.js +4 -0
  112. package/dist/core/common/persistence/persistence.tokens.js.map +1 -0
  113. package/dist/core/common/persistence/policies/audit.policy.d.ts +8 -0
  114. package/dist/core/common/persistence/policies/audit.policy.js +37 -0
  115. package/dist/core/common/persistence/policies/audit.policy.js.map +1 -0
  116. package/dist/core/common/persistence/policies/password.policy.d.ts +3 -0
  117. package/dist/core/common/persistence/policies/password.policy.js +46 -0
  118. package/dist/core/common/persistence/policies/password.policy.js.map +1 -0
  119. package/dist/core/common/persistence/policies/role-guard.policy.d.ts +3 -0
  120. package/dist/core/common/persistence/policies/role-guard.policy.js +46 -0
  121. package/dist/core/common/persistence/policies/role-guard.policy.js.map +1 -0
  122. package/dist/core/common/persistence/policies/system-role.policy.d.ts +5 -0
  123. package/dist/core/common/persistence/policies/system-role.policy.js +46 -0
  124. package/dist/core/common/persistence/policies/system-role.policy.js.map +1 -0
  125. package/dist/core/common/persistence/policies/tenant.policy.d.ts +19 -0
  126. package/dist/core/common/persistence/policies/tenant.policy.js +120 -0
  127. package/dist/core/common/persistence/policies/tenant.policy.js.map +1 -0
  128. package/dist/core/common/persistence/routed-model.guard.d.ts +4 -0
  129. package/dist/core/common/persistence/routed-model.guard.js +73 -0
  130. package/dist/core/common/persistence/routed-model.guard.js.map +1 -0
  131. package/dist/core/common/persistence/sql/mysql/mysql-data-store.d.ts +46 -0
  132. package/dist/core/common/persistence/sql/mysql/mysql-data-store.js +350 -0
  133. package/dist/core/common/persistence/sql/mysql/mysql-data-store.js.map +1 -0
  134. package/dist/core/common/persistence/sql/mysql/mysql-executor.d.ts +13 -0
  135. package/dist/core/common/persistence/sql/mysql/mysql-executor.js +194 -0
  136. package/dist/core/common/persistence/sql/mysql/mysql-executor.js.map +1 -0
  137. package/dist/core/common/persistence/sql/mysql/mysql-lock-store.d.ts +11 -0
  138. package/dist/core/common/persistence/sql/mysql/mysql-lock-store.js +55 -0
  139. package/dist/core/common/persistence/sql/mysql/mysql-lock-store.js.map +1 -0
  140. package/dist/core/common/persistence/sql/mysql/mysql-schema.compiler.d.ts +36 -0
  141. package/dist/core/common/persistence/sql/mysql/mysql-schema.compiler.js +288 -0
  142. package/dist/core/common/persistence/sql/mysql/mysql-schema.compiler.js.map +1 -0
  143. package/dist/core/common/persistence/sql/mysql/mysql-schema.migrator.d.ts +19 -0
  144. package/dist/core/common/persistence/sql/mysql/mysql-schema.migrator.js +328 -0
  145. package/dist/core/common/persistence/sql/mysql/mysql-schema.migrator.js.map +1 -0
  146. package/dist/core/common/persistence/sql/mysql/mysql-session.d.ts +13 -0
  147. package/dist/core/common/persistence/sql/mysql/mysql-session.js +85 -0
  148. package/dist/core/common/persistence/sql/mysql/mysql-session.js.map +1 -0
  149. package/dist/core/common/persistence/sql/mysql/mysql-update.compiler.d.ts +9 -0
  150. package/dist/core/common/persistence/sql/mysql/mysql-update.compiler.js +264 -0
  151. package/dist/core/common/persistence/sql/mysql/mysql-update.compiler.js.map +1 -0
  152. package/dist/core/common/persistence/sql/mysql/mysql-where.compiler.d.ts +20 -0
  153. package/dist/core/common/persistence/sql/mysql/mysql-where.compiler.js +519 -0
  154. package/dist/core/common/persistence/sql/mysql/mysql-where.compiler.js.map +1 -0
  155. package/dist/core/common/persistence/sql/postgres/postgres-lock-store.d.ts +11 -0
  156. package/dist/core/common/persistence/sql/postgres/postgres-lock-store.js +44 -0
  157. package/dist/core/common/persistence/sql/postgres/postgres-lock-store.js.map +1 -0
  158. package/dist/core/common/persistence/sql/postgres/postgres-schema.compiler.d.ts +42 -0
  159. package/dist/core/common/persistence/sql/postgres/postgres-schema.compiler.js +220 -0
  160. package/dist/core/common/persistence/sql/postgres/postgres-schema.compiler.js.map +1 -0
  161. package/dist/core/common/persistence/sql/postgres/postgres-schema.migrator.d.ts +12 -0
  162. package/dist/core/common/persistence/sql/postgres/postgres-schema.migrator.js +315 -0
  163. package/dist/core/common/persistence/sql/postgres/postgres-schema.migrator.js.map +1 -0
  164. package/dist/core/common/persistence/sql/postgres/postgres-update.compiler.d.ts +5 -0
  165. package/dist/core/common/persistence/sql/postgres/postgres-update.compiler.js +225 -0
  166. package/dist/core/common/persistence/sql/postgres/postgres-update.compiler.js.map +1 -0
  167. package/dist/core/common/persistence/sql/postgres/postgres-where.compiler.d.ts +13 -0
  168. package/dist/core/common/persistence/sql/postgres/postgres-where.compiler.js +484 -0
  169. package/dist/core/common/persistence/sql/postgres/postgres-where.compiler.js.map +1 -0
  170. package/dist/core/common/persistence/sql/sql-cast.d.ts +2 -0
  171. package/dist/core/common/persistence/sql/sql-cast.js +194 -0
  172. package/dist/core/common/persistence/sql/sql-cast.js.map +1 -0
  173. package/dist/core/common/persistence/sql/sql-data-store.d.ts +79 -0
  174. package/dist/core/common/persistence/sql/sql-data-store.js +592 -0
  175. package/dist/core/common/persistence/sql/sql-data-store.js.map +1 -0
  176. package/dist/core/common/persistence/sql/sql-dialect.d.ts +20 -0
  177. package/dist/core/common/persistence/sql/sql-dialect.js +38 -0
  178. package/dist/core/common/persistence/sql/sql-dialect.js.map +1 -0
  179. package/dist/core/common/persistence/sql/sql-errors.d.ts +17 -0
  180. package/dist/core/common/persistence/sql/sql-errors.js +25 -0
  181. package/dist/core/common/persistence/sql/sql-errors.js.map +1 -0
  182. package/dist/core/common/persistence/sql/sql-executor.factory.d.ts +11 -0
  183. package/dist/core/common/persistence/sql/sql-executor.factory.js +199 -0
  184. package/dist/core/common/persistence/sql/sql-executor.factory.js.map +1 -0
  185. package/dist/core/common/persistence/sql/sql-executor.interface.d.ts +32 -0
  186. package/dist/core/common/persistence/sql/sql-executor.interface.js +2 -0
  187. package/dist/core/common/persistence/sql/sql-executor.interface.js.map +1 -0
  188. package/dist/core/common/persistence/sql/sql-naming.d.ts +15 -0
  189. package/dist/core/common/persistence/sql/sql-naming.js +90 -0
  190. package/dist/core/common/persistence/sql/sql-naming.js.map +1 -0
  191. package/dist/core/common/persistence/sql/sql-schema.shared.d.ts +25 -0
  192. package/dist/core/common/persistence/sql/sql-schema.shared.js +69 -0
  193. package/dist/core/common/persistence/sql/sql-schema.shared.js.map +1 -0
  194. package/dist/core/common/persistence/sql/sql-session.d.ts +6 -0
  195. package/dist/core/common/persistence/sql/sql-session.js +78 -0
  196. package/dist/core/common/persistence/sql/sql-session.js.map +1 -0
  197. package/dist/core/common/persistence/sql/where-shared.d.ts +18 -0
  198. package/dist/core/common/persistence/sql/where-shared.js +93 -0
  199. package/dist/core/common/persistence/sql/where-shared.js.map +1 -0
  200. package/dist/core/common/persistence/store-guards.d.ts +10 -0
  201. package/dist/core/common/persistence/store-guards.js +49 -0
  202. package/dist/core/common/persistence/store-guards.js.map +1 -0
  203. package/dist/core/common/persistence/store-upsert.d.ts +2 -0
  204. package/dist/core/common/persistence/store-upsert.js +20 -0
  205. package/dist/core/common/persistence/store-upsert.js.map +1 -0
  206. package/dist/core/common/persistence/unavailable-store.d.ts +2 -0
  207. package/dist/core/common/persistence/unavailable-store.js +53 -0
  208. package/dist/core/common/persistence/unavailable-store.js.map +1 -0
  209. package/dist/core/common/persistence/unsupported-capability.error.d.ts +3 -0
  210. package/dist/core/common/persistence/unsupported-capability.error.js +4 -0
  211. package/dist/core/common/persistence/unsupported-capability.error.js.map +1 -0
  212. package/dist/core/common/plugins/mongoose-audit-fields.plugin.js +24 -68
  213. package/dist/core/common/plugins/mongoose-audit-fields.plugin.js.map +1 -1
  214. package/dist/core/common/plugins/mongoose-id.plugin.js +3 -0
  215. package/dist/core/common/plugins/mongoose-id.plugin.js.map +1 -1
  216. package/dist/core/common/plugins/mongoose-password.plugin.d.ts +1 -3
  217. package/dist/core/common/plugins/mongoose-password.plugin.js +2 -45
  218. package/dist/core/common/plugins/mongoose-password.plugin.js.map +1 -1
  219. package/dist/core/common/plugins/mongoose-role-guard.plugin.js +5 -46
  220. package/dist/core/common/plugins/mongoose-role-guard.plugin.js.map +1 -1
  221. package/dist/core/common/plugins/mongoose-system-role.plugin.js +2 -43
  222. package/dist/core/common/plugins/mongoose-system-role.plugin.js.map +1 -1
  223. package/dist/core/common/plugins/mongoose-tenant.plugin.js +10 -70
  224. package/dist/core/common/plugins/mongoose-tenant.plugin.js.map +1 -1
  225. package/dist/core/common/scalars/upload.scalar.js +1 -1
  226. package/dist/core/common/scalars/upload.scalar.js.map +1 -1
  227. package/dist/core/common/services/core-cron-jobs.initializer.js +1 -1
  228. package/dist/core/common/services/core-cron-jobs.initializer.js.map +1 -1
  229. package/dist/core/common/services/core-cron-jobs.service.d.ts +1 -0
  230. package/dist/core/common/services/core-cron-jobs.service.js +23 -14
  231. package/dist/core/common/services/core-cron-jobs.service.js.map +1 -1
  232. package/dist/core/common/services/crud.service.d.ts +4 -1
  233. package/dist/core/common/services/crud.service.js +132 -23
  234. package/dist/core/common/services/crud.service.js.map +1 -1
  235. package/dist/core/common/services/model-doc.service.js +1 -1
  236. package/dist/core/common/services/model-doc.service.js.map +1 -1
  237. package/dist/core/common/services/module.service.d.ts +9 -2
  238. package/dist/core/common/services/module.service.js +51 -6
  239. package/dist/core/common/services/module.service.js.map +1 -1
  240. package/dist/core/common/types/field-selection.type.d.ts +1 -1
  241. package/dist/core/common/types/id.type.d.ts +4 -4
  242. package/dist/core/common/types/object-id-like.type.d.ts +3 -0
  243. package/dist/core/common/types/object-id-like.type.js +2 -0
  244. package/dist/core/common/types/object-id-like.type.js.map +1 -0
  245. package/dist/core/common/types/populate-config.type.d.ts +1 -1
  246. package/dist/core/common/types/string-or-object-id.type.d.ts +2 -2
  247. package/dist/core/modules/ai/core-ai.constants.d.ts +4 -0
  248. package/dist/core/modules/ai/core-ai.constants.js +4 -0
  249. package/dist/core/modules/ai/core-ai.constants.js.map +1 -1
  250. package/dist/core/modules/ai/core-ai.module.js +21 -17
  251. package/dist/core/modules/ai/core-ai.module.js.map +1 -1
  252. package/dist/core/modules/ai/models/core-ai-budget-limit.model.d.ts +2 -92
  253. package/dist/core/modules/ai/models/core-ai-budget-limit.model.js +1 -1
  254. package/dist/core/modules/ai/models/core-ai-budget-limit.model.js.map +1 -1
  255. package/dist/core/modules/ai/models/core-ai-connection-preference.model.d.ts +2 -87
  256. package/dist/core/modules/ai/models/core-ai-connection-preference.model.js +1 -1
  257. package/dist/core/modules/ai/models/core-ai-connection-preference.model.js.map +1 -1
  258. package/dist/core/modules/ai/models/core-ai-connection.model.d.ts +2 -177
  259. package/dist/core/modules/ai/models/core-ai-connection.model.js +1 -1
  260. package/dist/core/modules/ai/models/core-ai-connection.model.js.map +1 -1
  261. package/dist/core/modules/ai/models/core-ai-conversation.model.d.ts +2 -92
  262. package/dist/core/modules/ai/models/core-ai-conversation.model.js +3 -4
  263. package/dist/core/modules/ai/models/core-ai-conversation.model.js.map +1 -1
  264. package/dist/core/modules/ai/models/core-ai-interaction.model.d.ts +2 -120
  265. package/dist/core/modules/ai/models/core-ai-interaction.model.js +2 -3
  266. package/dist/core/modules/ai/models/core-ai-interaction.model.js.map +1 -1
  267. package/dist/core/modules/ai/models/core-ai-mcp-oauth.models.d.ts +3 -0
  268. package/dist/core/modules/ai/models/core-ai-mcp-oauth.models.js +21 -0
  269. package/dist/core/modules/ai/models/core-ai-mcp-oauth.models.js.map +1 -0
  270. package/dist/core/modules/ai/models/core-ai-mode.model.d.ts +2 -102
  271. package/dist/core/modules/ai/models/core-ai-mode.model.js +1 -1
  272. package/dist/core/modules/ai/models/core-ai-mode.model.js.map +1 -1
  273. package/dist/core/modules/ai/models/core-ai-prompt-hint.model.d.ts +2 -97
  274. package/dist/core/modules/ai/models/core-ai-prompt-hint.model.js +1 -1
  275. package/dist/core/modules/ai/models/core-ai-prompt-hint.model.js.map +1 -1
  276. package/dist/core/modules/ai/models/core-ai-prompt.model.d.ts +2 -112
  277. package/dist/core/modules/ai/models/core-ai-prompt.model.js +1 -1
  278. package/dist/core/modules/ai/models/core-ai-prompt.model.js.map +1 -1
  279. package/dist/core/modules/ai/models/core-ai-slot.model.d.ts +2 -112
  280. package/dist/core/modules/ai/models/core-ai-slot.model.js +1 -1
  281. package/dist/core/modules/ai/models/core-ai-slot.model.js.map +1 -1
  282. package/dist/core/modules/ai/models/core-ai-tool-grant.model.d.ts +2 -97
  283. package/dist/core/modules/ai/models/core-ai-tool-grant.model.js +1 -1
  284. package/dist/core/modules/ai/models/core-ai-tool-grant.model.js.map +1 -1
  285. package/dist/core/modules/ai/models/core-ai-tool-policy.model.d.ts +2 -103
  286. package/dist/core/modules/ai/models/core-ai-tool-policy.model.js +1 -1
  287. package/dist/core/modules/ai/models/core-ai-tool-policy.model.js.map +1 -1
  288. package/dist/core/modules/ai/services/core-ai-budget.service.d.ts +3 -1
  289. package/dist/core/modules/ai/services/core-ai-budget.service.js +15 -5
  290. package/dist/core/modules/ai/services/core-ai-budget.service.js.map +1 -1
  291. package/dist/core/modules/ai/services/core-ai-connection-preference.service.d.ts +1 -1
  292. package/dist/core/modules/ai/services/core-ai-connection-preference.service.js +6 -10
  293. package/dist/core/modules/ai/services/core-ai-connection-preference.service.js.map +1 -1
  294. package/dist/core/modules/ai/services/core-ai-connection.service.d.ts +1 -1
  295. package/dist/core/modules/ai/services/core-ai-connection.service.js +20 -42
  296. package/dist/core/modules/ai/services/core-ai-connection.service.js.map +1 -1
  297. package/dist/core/modules/ai/services/core-ai-conversation.service.d.ts +1 -1
  298. package/dist/core/modules/ai/services/core-ai-conversation.service.js +28 -29
  299. package/dist/core/modules/ai/services/core-ai-conversation.service.js.map +1 -1
  300. package/dist/core/modules/ai/services/core-ai-interaction.service.d.ts +1 -1
  301. package/dist/core/modules/ai/services/core-ai-interaction.service.js +3 -4
  302. package/dist/core/modules/ai/services/core-ai-interaction.service.js.map +1 -1
  303. package/dist/core/modules/ai/services/core-ai-mcp-oauth.service.d.ts +8 -0
  304. package/dist/core/modules/ai/services/core-ai-mcp-oauth.service.js +70 -18
  305. package/dist/core/modules/ai/services/core-ai-mcp-oauth.service.js.map +1 -1
  306. package/dist/core/modules/ai/services/core-ai-mode.service.d.ts +1 -1
  307. package/dist/core/modules/ai/services/core-ai-mode.service.js +3 -7
  308. package/dist/core/modules/ai/services/core-ai-mode.service.js.map +1 -1
  309. package/dist/core/modules/ai/services/core-ai-prompt-hint.service.d.ts +8 -1
  310. package/dist/core/modules/ai/services/core-ai-prompt-hint.service.js +32 -26
  311. package/dist/core/modules/ai/services/core-ai-prompt-hint.service.js.map +1 -1
  312. package/dist/core/modules/ai/services/core-ai-prompt.service.d.ts +1 -1
  313. package/dist/core/modules/ai/services/core-ai-prompt.service.js +10 -13
  314. package/dist/core/modules/ai/services/core-ai-prompt.service.js.map +1 -1
  315. package/dist/core/modules/ai/services/core-ai-slot.service.d.ts +1 -1
  316. package/dist/core/modules/ai/services/core-ai-slot.service.js +14 -25
  317. package/dist/core/modules/ai/services/core-ai-slot.service.js.map +1 -1
  318. package/dist/core/modules/ai/services/core-ai-tool-grant.service.d.ts +1 -1
  319. package/dist/core/modules/ai/services/core-ai-tool-grant.service.js +6 -18
  320. package/dist/core/modules/ai/services/core-ai-tool-grant.service.js.map +1 -1
  321. package/dist/core/modules/ai/services/core-ai-tool-policy.service.d.ts +1 -1
  322. package/dist/core/modules/ai/services/core-ai-tool-policy.service.js +4 -8
  323. package/dist/core/modules/ai/services/core-ai-tool-policy.service.js.map +1 -1
  324. package/dist/core/modules/api-token/core-api-token.model.js +1 -1
  325. package/dist/core/modules/api-token/core-api-token.model.js.map +1 -1
  326. package/dist/core/modules/api-token/core-api-token.module.js +3 -2
  327. package/dist/core/modules/api-token/core-api-token.module.js.map +1 -1
  328. package/dist/core/modules/api-token/core-api-token.service.d.ts +8 -2
  329. package/dist/core/modules/api-token/core-api-token.service.js +106 -39
  330. package/dist/core/modules/api-token/core-api-token.service.js.map +1 -1
  331. package/dist/core/modules/auth/core-auth.module.js +2 -0
  332. package/dist/core/modules/auth/core-auth.module.js.map +1 -1
  333. package/dist/core/modules/auth/guards/legacy-auth-rate-limit.guard.js +1 -2
  334. package/dist/core/modules/auth/guards/legacy-auth-rate-limit.guard.js.map +1 -1
  335. package/dist/core/modules/auth/guards/role-guard.token.d.ts +1 -0
  336. package/dist/core/modules/auth/guards/role-guard.token.js +2 -0
  337. package/dist/core/modules/auth/guards/role-guard.token.js.map +1 -0
  338. package/dist/core/modules/auth/services/core-auth.service.js +4 -2
  339. package/dist/core/modules/auth/services/core-auth.service.js.map +1 -1
  340. package/dist/core/modules/better-auth/better-auth-sql.helper.d.ts +6 -0
  341. package/dist/core/modules/better-auth/better-auth-sql.helper.js +113 -0
  342. package/dist/core/modules/better-auth/better-auth-sql.helper.js.map +1 -0
  343. package/dist/core/modules/better-auth/better-auth-token.service.d.ts +3 -1
  344. package/dist/core/modules/better-auth/better-auth-token.service.js +15 -24
  345. package/dist/core/modules/better-auth/better-auth-token.service.js.map +1 -1
  346. package/dist/core/modules/better-auth/better-auth.config.d.ts +7 -0
  347. package/dist/core/modules/better-auth/better-auth.config.js +16 -5
  348. package/dist/core/modules/better-auth/better-auth.config.js.map +1 -1
  349. package/dist/core/modules/better-auth/better-auth.types.d.ts +1 -1
  350. package/dist/core/modules/better-auth/core-better-auth-api.middleware.d.ts +1 -0
  351. package/dist/core/modules/better-auth/core-better-auth-api.middleware.js +6 -1
  352. package/dist/core/modules/better-auth/core-better-auth-api.middleware.js.map +1 -1
  353. package/dist/core/modules/better-auth/core-better-auth-challenge.service.js +30 -15
  354. package/dist/core/modules/better-auth/core-better-auth-challenge.service.js.map +1 -1
  355. package/dist/core/modules/better-auth/core-better-auth-mongo.users.d.ts +10 -0
  356. package/dist/core/modules/better-auth/core-better-auth-mongo.users.js +24 -0
  357. package/dist/core/modules/better-auth/core-better-auth-mongo.users.js.map +1 -0
  358. package/dist/core/modules/better-auth/core-better-auth-sql.registry.d.ts +3 -0
  359. package/dist/core/modules/better-auth/core-better-auth-sql.registry.js +8 -0
  360. package/dist/core/modules/better-auth/core-better-auth-sql.registry.js.map +1 -0
  361. package/dist/core/modules/better-auth/core-better-auth-sql.store.d.ts +71 -0
  362. package/dist/core/modules/better-auth/core-better-auth-sql.store.js +190 -0
  363. package/dist/core/modules/better-auth/core-better-auth-sql.store.js.map +1 -0
  364. package/dist/core/modules/better-auth/core-better-auth-user.mapper.d.ts +24 -1
  365. package/dist/core/modules/better-auth/core-better-auth-user.mapper.js +308 -32
  366. package/dist/core/modules/better-auth/core-better-auth-user.mapper.js.map +1 -1
  367. package/dist/core/modules/better-auth/core-better-auth.module.d.ts +2 -0
  368. package/dist/core/modules/better-auth/core-better-auth.module.js +54 -32
  369. package/dist/core/modules/better-auth/core-better-auth.module.js.map +1 -1
  370. package/dist/core/modules/better-auth/core-better-auth.service.d.ts +7 -2
  371. package/dist/core/modules/better-auth/core-better-auth.service.js +61 -9
  372. package/dist/core/modules/better-auth/core-better-auth.service.js.map +1 -1
  373. package/dist/core/modules/file/core-file-info.model.d.ts +1 -2
  374. package/dist/core/modules/file/core-file-info.model.js +2 -2
  375. package/dist/core/modules/file/core-file-info.model.js.map +1 -1
  376. package/dist/core/modules/file/core-file.service.d.ts +5 -3
  377. package/dist/core/modules/file/core-file.service.js +16 -9
  378. package/dist/core/modules/file/core-file.service.js.map +1 -1
  379. package/dist/core/modules/file/file-metadata.helper.d.ts +1 -1
  380. package/dist/core/modules/file/file-metadata.helper.js +2 -2
  381. package/dist/core/modules/file/file-metadata.helper.js.map +1 -1
  382. package/dist/core/modules/file/file-metadata.models.d.ts +35 -0
  383. package/dist/core/modules/file/file-metadata.models.js +20 -0
  384. package/dist/core/modules/file/file-metadata.models.js.map +1 -0
  385. package/dist/core/modules/file/file-metadata.store.d.ts +6 -0
  386. package/dist/core/modules/file/file-metadata.store.js +77 -0
  387. package/dist/core/modules/file/file-metadata.store.js.map +1 -0
  388. package/dist/core/modules/file/file-storage.helper.d.ts +1 -0
  389. package/dist/core/modules/file/file-storage.helper.js +34 -0
  390. package/dist/core/modules/file/file-storage.helper.js.map +1 -1
  391. package/dist/core/modules/file/filesystem-file.helper.d.ts +1 -1
  392. package/dist/core/modules/file/filesystem-file.helper.js +4 -4
  393. package/dist/core/modules/file/filesystem-file.helper.js.map +1 -1
  394. package/dist/core/modules/file/s3-file.helper.d.ts +1 -1
  395. package/dist/core/modules/file/s3-file.helper.js +5 -5
  396. package/dist/core/modules/file/s3-file.helper.js.map +1 -1
  397. package/dist/core/modules/health-check/core-health-check.module.js +12 -2
  398. package/dist/core/modules/health-check/core-health-check.module.js.map +1 -1
  399. package/dist/core/modules/health-check/core-health-check.service.d.ts +4 -3
  400. package/dist/core/modules/health-check/core-health-check.service.js +26 -5
  401. package/dist/core/modules/health-check/core-health-check.service.js.map +1 -1
  402. package/dist/core/modules/hub/core-hub.controller.d.ts +1 -0
  403. package/dist/core/modules/hub/core-hub.controller.js +10 -0
  404. package/dist/core/modules/hub/core-hub.controller.js.map +1 -1
  405. package/dist/core/modules/hub/core-hub.service.js +1 -1
  406. package/dist/core/modules/hub/core-hub.service.js.map +1 -1
  407. package/dist/core/modules/hub/helpers/hub-client-js.helper.js +23 -0
  408. package/dist/core/modules/hub/helpers/hub-client-js.helper.js.map +1 -1
  409. package/dist/core/modules/hub/hub-action-messages.d.ts +2 -0
  410. package/dist/core/modules/hub/hub-action-messages.js +2 -0
  411. package/dist/core/modules/hub/hub-action-messages.js.map +1 -1
  412. package/dist/core/modules/hub/hub-nav.js +1 -0
  413. package/dist/core/modules/hub/hub-nav.js.map +1 -1
  414. package/dist/core/modules/hub/interfaces/hub-panels.interface.d.ts +17 -1
  415. package/dist/core/modules/hub/services/core-hub-db.service.d.ts +6 -1
  416. package/dist/core/modules/hub/services/core-hub-db.service.js +16 -14
  417. package/dist/core/modules/hub/services/core-hub-db.service.js.map +1 -1
  418. package/dist/core/modules/hub/services/core-hub-migrations.service.d.ts +5 -0
  419. package/dist/core/modules/hub/services/core-hub-migrations.service.js +74 -1
  420. package/dist/core/modules/hub/services/core-hub-migrations.service.js.map +1 -1
  421. package/dist/core/modules/hub/services/core-hub-sources.service.d.ts +2 -1
  422. package/dist/core/modules/hub/services/core-hub-sources.service.js +32 -0
  423. package/dist/core/modules/hub/services/core-hub-sources.service.js.map +1 -1
  424. package/dist/core/modules/hub/services/hub-query-profiler.service.js +1 -1
  425. package/dist/core/modules/hub/services/hub-query-profiler.service.js.map +1 -1
  426. package/dist/core/modules/migrate/cli/migrate-cli.d.ts +2 -0
  427. package/dist/core/modules/migrate/cli/migrate-cli.js +35 -1
  428. package/dist/core/modules/migrate/cli/migrate-cli.js.map +1 -1
  429. package/dist/core/modules/migrate/index.d.ts +3 -0
  430. package/dist/core/modules/migrate/index.js +3 -0
  431. package/dist/core/modules/migrate/index.js.map +1 -1
  432. package/dist/core/modules/migrate/migration-runner.d.ts +2 -2
  433. package/dist/core/modules/migrate/migration-runner.js.map +1 -1
  434. package/dist/core/modules/migrate/migration-state-store.interface.d.ts +16 -0
  435. package/dist/core/modules/migrate/migration-state-store.interface.js +2 -0
  436. package/dist/core/modules/migrate/migration-state-store.interface.js.map +1 -0
  437. package/dist/core/modules/migrate/migration.helper.d.ts +3 -2
  438. package/dist/core/modules/migrate/migration.helper.js +21 -6
  439. package/dist/core/modules/migrate/migration.helper.js.map +1 -1
  440. package/dist/core/modules/migrate/mongo-state-store.d.ts +5 -12
  441. package/dist/core/modules/migrate/mongo-state-store.js +30 -24
  442. package/dist/core/modules/migrate/mongo-state-store.js.map +1 -1
  443. package/dist/core/modules/migrate/sql-migration.helper.d.ts +4 -0
  444. package/dist/core/modules/migrate/sql-migration.helper.js +34 -0
  445. package/dist/core/modules/migrate/sql-migration.helper.js.map +1 -0
  446. package/dist/core/modules/migrate/sql-state-store.d.ts +24 -0
  447. package/dist/core/modules/migrate/sql-state-store.js +129 -0
  448. package/dist/core/modules/migrate/sql-state-store.js.map +1 -0
  449. package/dist/core/modules/system-setup/core-system-setup.service.d.ts +8 -0
  450. package/dist/core/modules/system-setup/core-system-setup.service.js +41 -25
  451. package/dist/core/modules/system-setup/core-system-setup.service.js.map +1 -1
  452. package/dist/core/modules/tenant/core-tenant-member.model.js +1 -1
  453. package/dist/core/modules/tenant/core-tenant-member.model.js.map +1 -1
  454. package/dist/core/modules/tenant/core-tenant-member.store.d.ts +2 -0
  455. package/dist/core/modules/tenant/core-tenant-member.store.js +6 -0
  456. package/dist/core/modules/tenant/core-tenant-member.store.js.map +1 -0
  457. package/dist/core/modules/tenant/core-tenant.guard.d.ts +8 -3
  458. package/dist/core/modules/tenant/core-tenant.guard.js +57 -28
  459. package/dist/core/modules/tenant/core-tenant.guard.js.map +1 -1
  460. package/dist/core/modules/tenant/core-tenant.module.js +3 -2
  461. package/dist/core/modules/tenant/core-tenant.module.js.map +1 -1
  462. package/dist/core/modules/tenant/core-tenant.service.d.ts +3 -1
  463. package/dist/core/modules/tenant/core-tenant.service.js +48 -28
  464. package/dist/core/modules/tenant/core-tenant.service.js.map +1 -1
  465. package/dist/core/modules/tus/core-tus.service.d.ts +1 -1
  466. package/dist/core/modules/tus/core-tus.service.js +8 -7
  467. package/dist/core/modules/tus/core-tus.service.js.map +1 -1
  468. package/dist/core/modules/tus/tus.module.js +1 -1
  469. package/dist/core/modules/tus/tus.module.js.map +1 -1
  470. package/dist/core/modules/user/core-user.model.d.ts +1 -1
  471. package/dist/core/modules/user/core-user.model.js +1 -1
  472. package/dist/core/modules/user/core-user.model.js.map +1 -1
  473. package/dist/core/modules/user/core-user.service.d.ts +3 -1
  474. package/dist/core/modules/user/core-user.service.js +71 -16
  475. package/dist/core/modules/user/core-user.service.js.map +1 -1
  476. package/dist/core.module.js +39 -5
  477. package/dist/core.module.js.map +1 -1
  478. package/dist/index.d.ts +26 -0
  479. package/dist/index.js +26 -0
  480. package/dist/index.js.map +1 -1
  481. package/dist/server/common/models/persistence.model.d.ts +1 -1
  482. package/dist/server/common/models/persistence.model.js +3 -3
  483. package/dist/server/common/models/persistence.model.js.map +1 -1
  484. package/dist/server/modules/file/file-info.model.d.ts +1 -77
  485. package/dist/server/modules/file/file-info.model.js +1 -1
  486. package/dist/server/modules/file/file-info.model.js.map +1 -1
  487. package/dist/server/modules/file/file.service.js +1 -1
  488. package/dist/server/modules/file/file.service.js.map +1 -1
  489. package/dist/server/modules/user/user.model.d.ts +2 -186
  490. package/dist/server/modules/user/user.model.js +4 -5
  491. package/dist/server/modules/user/user.model.js.map +1 -1
  492. package/dist/server/modules/user/user.module.js +4 -3
  493. package/dist/server/modules/user/user.module.js.map +1 -1
  494. package/dist/server/modules/user/user.service.d.ts +1 -1
  495. package/dist/server/modules/user/user.service.js +5 -8
  496. package/dist/server/modules/user/user.service.js.map +1 -1
  497. package/dist/test/test.helper.js +2 -2
  498. package/dist/test/test.helper.js.map +1 -1
  499. package/dist/types/graphql-upload.d.ts +10 -7
  500. package/docs/REQUEST-LIFECYCLE.md +6 -3
  501. package/docs/choosing-a-database.md +107 -0
  502. package/docs/native-driver-security.md +29 -0
  503. package/docs/security-overrides.md +15 -6
  504. package/migration-guides/12.0.x-to-12.1.x.md +255 -0
  505. package/package.json +75 -29
  506. package/src/core/common/decorators/unified-field.decorator.ts +11 -1
  507. package/src/core/common/filters/mongoose-cast-error.filter.ts +12 -6
  508. package/src/core/common/helpers/db.helper.ts +40 -25
  509. package/src/core/common/helpers/decorator.helper.ts +1 -1
  510. package/src/core/common/helpers/filter.helper.ts +2 -1
  511. package/src/core/common/helpers/gridfs.helper.ts +28 -9
  512. package/src/core/common/helpers/id.helper.ts +21 -4
  513. package/src/core/common/helpers/model.helper.ts +5 -6
  514. package/src/core/common/helpers/service.helper.ts +3 -3
  515. package/src/core/common/interfaces/server-options.interface.ts +118 -10
  516. package/src/core/common/interfaces/service-options.interface.ts +2 -2
  517. package/src/core/common/models/core-persistence.model.ts +3 -3
  518. package/src/core/common/persistence/core-persistence.lifecycle.ts +47 -0
  519. package/src/core/common/persistence/core-persistence.module.ts +109 -0
  520. package/src/core/common/persistence/data-source.config.ts +271 -0
  521. package/src/core/common/persistence/data-source.runtime.ts +351 -0
  522. package/src/core/common/persistence/data-store.interface.ts +155 -0
  523. package/src/core/common/persistence/expiry-sweep.ts +105 -0
  524. package/src/core/common/persistence/id-format.ts +43 -0
  525. package/src/core/common/persistence/infrastructure-locks.ts +66 -0
  526. package/src/core/common/persistence/inject-store.decorator.ts +16 -0
  527. package/src/core/common/persistence/lock-store.interface.ts +17 -0
  528. package/src/core/common/persistence/model-descriptor.interface.ts +90 -0
  529. package/src/core/common/persistence/model-metadata.registry.ts +285 -0
  530. package/src/core/common/persistence/mongo/collection-name.ts +87 -0
  531. package/src/core/common/persistence/mongo/declared-schema.view.ts +378 -0
  532. package/src/core/common/persistence/mongo/hex-object-id.ts +75 -0
  533. package/src/core/common/persistence/mongo/model-declarations.ts +135 -0
  534. package/src/core/common/persistence/mongo/mongo-packages.ts +130 -0
  535. package/src/core/common/persistence/mongo/mongoose-compat.ts +129 -0
  536. package/src/core/common/persistence/mongo/no-mongo-connection.module.ts +18 -0
  537. package/src/core/common/persistence/mongo-lock-store.ts +121 -0
  538. package/src/core/common/persistence/mongoose-data-store.ts +232 -0
  539. package/src/core/common/persistence/neutral-populate.ts +98 -0
  540. package/src/core/common/persistence/persisted-model.decorator.ts +61 -0
  541. package/src/core/common/persistence/persistence-runtime.registry.ts +152 -0
  542. package/src/core/common/persistence/persistence.tokens.ts +9 -0
  543. package/src/core/common/persistence/policies/audit.policy.ts +80 -0
  544. package/src/core/common/persistence/policies/password.policy.ts +69 -0
  545. package/src/core/common/persistence/policies/role-guard.policy.ts +74 -0
  546. package/src/core/common/persistence/policies/system-role.policy.ts +90 -0
  547. package/src/core/common/persistence/policies/tenant.policy.ts +245 -0
  548. package/src/core/common/persistence/routed-model.guard.ts +107 -0
  549. package/src/core/common/persistence/sql/mysql/mysql-data-store.ts +503 -0
  550. package/src/core/common/persistence/sql/mysql/mysql-executor.ts +281 -0
  551. package/src/core/common/persistence/sql/mysql/mysql-lock-store.ts +87 -0
  552. package/src/core/common/persistence/sql/mysql/mysql-schema.compiler.ts +424 -0
  553. package/src/core/common/persistence/sql/mysql/mysql-schema.migrator.ts +453 -0
  554. package/src/core/common/persistence/sql/mysql/mysql-session.ts +131 -0
  555. package/src/core/common/persistence/sql/mysql/mysql-update.compiler.ts +379 -0
  556. package/src/core/common/persistence/sql/mysql/mysql-where.compiler.ts +686 -0
  557. package/src/core/common/persistence/sql/postgres/postgres-lock-store.ts +76 -0
  558. package/src/core/common/persistence/sql/postgres/postgres-schema.compiler.ts +328 -0
  559. package/src/core/common/persistence/sql/postgres/postgres-schema.migrator.ts +448 -0
  560. package/src/core/common/persistence/sql/postgres/postgres-update.compiler.ts +310 -0
  561. package/src/core/common/persistence/sql/postgres/postgres-where.compiler.ts +638 -0
  562. package/src/core/common/persistence/sql/sql-cast.ts +227 -0
  563. package/src/core/common/persistence/sql/sql-data-store.ts +762 -0
  564. package/src/core/common/persistence/sql/sql-dialect.ts +85 -0
  565. package/src/core/common/persistence/sql/sql-errors.ts +49 -0
  566. package/src/core/common/persistence/sql/sql-executor.factory.ts +282 -0
  567. package/src/core/common/persistence/sql/sql-executor.interface.ts +57 -0
  568. package/src/core/common/persistence/sql/sql-naming.ts +133 -0
  569. package/src/core/common/persistence/sql/sql-schema.shared.ts +105 -0
  570. package/src/core/common/persistence/sql/sql-session.ts +158 -0
  571. package/src/core/common/persistence/sql/where-shared.ts +118 -0
  572. package/src/core/common/persistence/store-guards.ts +73 -0
  573. package/src/core/common/persistence/store-upsert.ts +36 -0
  574. package/src/core/common/persistence/unavailable-store.ts +63 -0
  575. package/src/core/common/persistence/unsupported-capability.error.ts +7 -0
  576. package/src/core/common/plugins/mongoose-audit-fields.plugin.ts +33 -74
  577. package/src/core/common/plugins/mongoose-id.plugin.ts +9 -0
  578. package/src/core/common/plugins/mongoose-password.plugin.ts +6 -62
  579. package/src/core/common/plugins/mongoose-role-guard.plugin.ts +11 -63
  580. package/src/core/common/plugins/mongoose-system-role.plugin.ts +7 -78
  581. package/src/core/common/plugins/mongoose-tenant.plugin.ts +23 -144
  582. package/src/core/common/scalars/upload.scalar.ts +8 -3
  583. package/src/core/common/services/core-cron-jobs.initializer.ts +1 -1
  584. package/src/core/common/services/core-cron-jobs.service.ts +33 -22
  585. package/src/core/common/services/crud.service.ts +166 -35
  586. package/src/core/common/services/model-doc.service.ts +1 -1
  587. package/src/core/common/services/module.service.ts +78 -6
  588. package/src/core/common/types/field-selection.type.ts +1 -1
  589. package/src/core/common/types/id.type.ts +2 -2
  590. package/src/core/common/types/object-id-like.type.ts +11 -0
  591. package/src/core/common/types/populate-config.type.ts +1 -1
  592. package/src/core/common/types/string-or-object-id.type.ts +2 -2
  593. package/src/core/modules/ai/README.md +15 -2
  594. package/src/core/modules/ai/core-ai.constants.ts +10 -0
  595. package/src/core/modules/ai/core-ai.module.ts +32 -17
  596. package/src/core/modules/ai/models/core-ai-budget-limit.model.ts +2 -2
  597. package/src/core/modules/ai/models/core-ai-connection-preference.model.ts +2 -2
  598. package/src/core/modules/ai/models/core-ai-connection.model.ts +2 -2
  599. package/src/core/modules/ai/models/core-ai-conversation.model.ts +8 -4
  600. package/src/core/modules/ai/models/core-ai-interaction.model.ts +3 -3
  601. package/src/core/modules/ai/models/core-ai-mcp-oauth.models.ts +46 -0
  602. package/src/core/modules/ai/models/core-ai-mode.model.ts +2 -2
  603. package/src/core/modules/ai/models/core-ai-prompt-hint.model.ts +2 -2
  604. package/src/core/modules/ai/models/core-ai-prompt.model.ts +2 -2
  605. package/src/core/modules/ai/models/core-ai-slot.model.ts +2 -2
  606. package/src/core/modules/ai/models/core-ai-tool-grant.model.ts +2 -2
  607. package/src/core/modules/ai/models/core-ai-tool-policy.model.ts +2 -2
  608. package/src/core/modules/ai/services/core-ai-budget.service.ts +22 -4
  609. package/src/core/modules/ai/services/core-ai-connection-preference.service.ts +6 -13
  610. package/src/core/modules/ai/services/core-ai-connection.service.ts +34 -44
  611. package/src/core/modules/ai/services/core-ai-conversation.service.ts +31 -29
  612. package/src/core/modules/ai/services/core-ai-interaction.service.ts +3 -3
  613. package/src/core/modules/ai/services/core-ai-mcp-oauth.service.ts +93 -20
  614. package/src/core/modules/ai/services/core-ai-mode.service.ts +3 -6
  615. package/src/core/modules/ai/services/core-ai-prompt-hint.service.ts +43 -26
  616. package/src/core/modules/ai/services/core-ai-prompt.service.ts +15 -12
  617. package/src/core/modules/ai/services/core-ai-slot.service.ts +20 -24
  618. package/src/core/modules/ai/services/core-ai-tool-grant.service.ts +17 -27
  619. package/src/core/modules/ai/services/core-ai-tool-policy.service.ts +7 -10
  620. package/src/core/modules/api-token/core-api-token.model.ts +1 -1
  621. package/src/core/modules/api-token/core-api-token.module.ts +4 -2
  622. package/src/core/modules/api-token/core-api-token.service.ts +118 -43
  623. package/src/core/modules/auth/core-auth.module.ts +2 -0
  624. package/src/core/modules/auth/guards/legacy-auth-rate-limit.guard.ts +4 -3
  625. package/src/core/modules/auth/guards/role-guard.token.ts +7 -0
  626. package/src/core/modules/auth/services/core-auth.service.ts +16 -2
  627. package/src/core/modules/better-auth/INTEGRATION-CHECKLIST.md +1 -1
  628. package/src/core/modules/better-auth/README.md +10 -1
  629. package/src/core/modules/better-auth/better-auth-sql.helper.ts +191 -0
  630. package/src/core/modules/better-auth/better-auth-token.service.ts +26 -35
  631. package/src/core/modules/better-auth/better-auth.config.ts +43 -7
  632. package/src/core/modules/better-auth/better-auth.types.ts +1 -1
  633. package/src/core/modules/better-auth/core-better-auth-api.middleware.ts +13 -1
  634. package/src/core/modules/better-auth/core-better-auth-challenge.service.ts +36 -18
  635. package/src/core/modules/better-auth/core-better-auth-mongo.users.ts +35 -0
  636. package/src/core/modules/better-auth/core-better-auth-sql.registry.ts +20 -0
  637. package/src/core/modules/better-auth/core-better-auth-sql.store.ts +309 -0
  638. package/src/core/modules/better-auth/core-better-auth-user.mapper.ts +418 -40
  639. package/src/core/modules/better-auth/core-better-auth.module.ts +71 -35
  640. package/src/core/modules/better-auth/core-better-auth.service.ts +81 -12
  641. package/src/core/modules/file/README.md +16 -3
  642. package/src/core/modules/file/core-file-info.model.ts +2 -2
  643. package/src/core/modules/file/core-file.service.ts +27 -18
  644. package/src/core/modules/file/file-metadata.helper.ts +7 -3
  645. package/src/core/modules/file/file-metadata.models.ts +44 -0
  646. package/src/core/modules/file/file-metadata.store.ts +109 -0
  647. package/src/core/modules/file/file-storage.helper.ts +47 -2
  648. package/src/core/modules/file/filesystem-file.helper.ts +11 -8
  649. package/src/core/modules/file/s3-file.helper.ts +11 -7
  650. package/src/core/modules/health-check/core-health-check.module.ts +16 -2
  651. package/src/core/modules/health-check/core-health-check.service.ts +25 -3
  652. package/src/core/modules/hub/README.md +20 -11
  653. package/src/core/modules/hub/core-hub.controller.ts +5 -0
  654. package/src/core/modules/hub/core-hub.service.ts +1 -1
  655. package/src/core/modules/hub/helpers/hub-client-js.helper.ts +23 -0
  656. package/src/core/modules/hub/hub-action-messages.ts +6 -0
  657. package/src/core/modules/hub/hub-nav.ts +1 -0
  658. package/src/core/modules/hub/interfaces/hub-panels.interface.ts +8 -1
  659. package/src/core/modules/hub/services/core-hub-db.service.ts +35 -17
  660. package/src/core/modules/hub/services/core-hub-migrations.service.ts +96 -2
  661. package/src/core/modules/hub/services/core-hub-sources.service.ts +47 -1
  662. package/src/core/modules/hub/services/hub-query-profiler.service.ts +1 -1
  663. package/src/core/modules/migrate/README.md +54 -0
  664. package/src/core/modules/migrate/cli/migrate-cli.ts +44 -3
  665. package/src/core/modules/migrate/index.ts +3 -0
  666. package/src/core/modules/migrate/migration-runner.ts +3 -2
  667. package/src/core/modules/migrate/migration-state-store.interface.ts +24 -0
  668. package/src/core/modules/migrate/migration.helper.ts +35 -10
  669. package/src/core/modules/migrate/mongo-state-store.ts +64 -65
  670. package/src/core/modules/migrate/sql-migration.helper.ts +48 -0
  671. package/src/core/modules/migrate/sql-state-store.ts +198 -0
  672. package/src/core/modules/system-setup/README.md +14 -2
  673. package/src/core/modules/system-setup/core-system-setup.service.ts +77 -45
  674. package/src/core/modules/tenant/README.md +9 -2
  675. package/src/core/modules/tenant/core-tenant-member.model.ts +1 -1
  676. package/src/core/modules/tenant/core-tenant-member.store.ts +13 -0
  677. package/src/core/modules/tenant/core-tenant.guard.ts +77 -24
  678. package/src/core/modules/tenant/core-tenant.module.ts +6 -3
  679. package/src/core/modules/tenant/core-tenant.service.ts +59 -42
  680. package/src/core/modules/tus/core-tus.service.ts +11 -12
  681. package/src/core/modules/tus/tus.module.ts +1 -1
  682. package/src/core/modules/user/core-user.model.ts +2 -2
  683. package/src/core/modules/user/core-user.service.ts +98 -20
  684. package/src/core.module.ts +60 -5
  685. package/src/index.ts +26 -0
  686. package/src/server/common/models/persistence.model.ts +4 -4
  687. package/src/server/modules/file/file-info.model.ts +1 -1
  688. package/src/server/modules/file/file.service.ts +1 -1
  689. package/src/server/modules/user/user.model.ts +10 -5
  690. package/src/server/modules/user/user.module.ts +9 -3
  691. package/src/server/modules/user/user.service.ts +9 -11
  692. package/src/test/test.helper.ts +2 -2
  693. package/src/types/graphql-upload.d.ts +10 -7
@@ -0,0 +1,686 @@
1
+ import type { Where } from '../../data-store.interface.js';
2
+ import type { FieldDescriptor, ModelDescriptor } from '../../model-descriptor.interface.js';
3
+ import { castFilterValue } from '../sql-cast.js';
4
+ import { QueryCastError, UnsupportedQueryError } from '../sql-errors.js';
5
+ import { columnName, quoteMysqlIdentifier, type SqlParamSink } from '../sql-naming.js';
6
+ import {
7
+ type BsonType,
8
+ bsonType,
9
+ COLUMN_TYPES,
10
+ COMPARISON,
11
+ type ComparisonOperator,
12
+ isOperatorObject,
13
+ isPlainObject,
14
+ itemOf,
15
+ REGEX_KINDS,
16
+ SCALAR_KINDS,
17
+ splitPath,
18
+ toJson,
19
+ } from '../where-shared.js';
20
+ import type { MysqlVariant } from './mysql-session.js';
21
+
22
+ /**
23
+ * Compiles the neutral filter (the Mongo-operator subset of plan §3.2) into a MySQL 8.4 / MariaDB 11.8 condition — the
24
+ * counterpart of `postgres-where.compiler.ts`, with the same three rules: identifiers come from the model descriptor
25
+ * (JSON paths are bound as parameters), every value is a parameter cast with Mongoose's rules, and what cannot be
26
+ * expressed is refused, never dropped. MongoDB's semantics are kept where PostgreSQL keeps them: `null` matches a
27
+ * missing value, `$ne`/`$nin` include missing values, a condition on an array matches when any element matches.
28
+ *
29
+ * Two things differ from PostgreSQL's SQL, both measured on both servers (plan phase 6):
30
+ * - **"Any element matches" is `(SELECT COUNT(*) FROM JSON_TABLE(…)) > 0`, never `EXISTS`.** MySQL 8.4 turns an
31
+ * `EXISTS` over a `JSON_TABLE` that reads the outer row into a semi-join and then finds NOTHING — silently. Counting
32
+ * is not rewritten.
33
+ * - **JSON values compare as JSON**: MySQL through `CAST(? AS JSON)` and `=`, MariaDB (no JSON type, no such cast)
34
+ * through `JSON_EQUALS()`. Strings compare byte-wise (`utf8mb4_bin`), as on MongoDB and PostgreSQL (`COLLATE "C"`).
35
+ */
36
+
37
+ export interface MysqlWhereOptions {
38
+ /** Table alias to qualify columns with */
39
+ alias?: string;
40
+ }
41
+
42
+ /** A value addressed by a filter path */
43
+ type Target =
44
+ /** A scalar column */
45
+ | { expr: string; field: FieldDescriptor; kind: 'column'; path: string }
46
+ /** One JSON value; `field` is its declared descriptor, absent for undeclared (Mixed) content */
47
+ | { expr: string; field?: FieldDescriptor; kind: 'json'; path: string }
48
+ /** A JSON array; `element` describes its items, absent for undeclared (Mixed) content */
49
+ | { element?: FieldDescriptor; expr: string; kind: 'array'; path: string }
50
+ /** A path inside the items of a JSON array of objects: matches when any item matches */
51
+ | { arrayExpr: string; inner: (item: string) => Target; kind: 'elements'; path: string };
52
+
53
+ /** How each JSON type `JSON_TYPE()` reports belongs to a BSON type (both servers report these names) */
54
+ const JSON_TYPES: Partial<Record<BsonType, string[]>> = {
55
+ array: ['ARRAY'],
56
+ bool: ['BOOLEAN'],
57
+ null: ['NULL'],
58
+ number: ['DECIMAL', 'DOUBLE', 'INTEGER', 'UNSIGNED INTEGER'],
59
+ object: ['OBJECT'],
60
+ string: ['STRING'],
61
+ };
62
+ const NUMBER_TYPES = `('DECIMAL', 'DOUBLE', 'INTEGER', 'UNSIGNED INTEGER')`;
63
+
64
+ /** The SQL that turns a bound JSON text into a JSON value on each server */
65
+ export function mysqlJsonValue(variant: MysqlVariant, placeholder: string): string {
66
+ return variant === 'mysql' ? `CAST(${placeholder} AS JSON)` : `JSON_EXTRACT(${placeholder}, '$')`;
67
+ }
68
+
69
+ /** JSON equality on each server — object key order does not matter, numbers compare by value */
70
+ export function mysqlJsonEquals(variant: MysqlVariant, left: string, rightJsonText: string): string {
71
+ return variant === 'mysql'
72
+ ? `${left} = ${mysqlJsonValue(variant, rightJsonText)}`
73
+ : `JSON_EQUALS(${left}, ${rightJsonText})`;
74
+ }
75
+
76
+ /** A JSON value as a number when it is one, NULL for any other type — the cast never runs on another type */
77
+ export function mysqlJsonNumber(expr: string): string {
78
+ return `(CASE WHEN JSON_TYPE(${expr}) IN ${NUMBER_TYPES} THEN CAST(JSON_UNQUOTE(${expr}) AS DOUBLE) END)`;
79
+ }
80
+
81
+ /**
82
+ * ORDER BY keys for a JSON value: by type in MongoDB's order (missing or null, numbers, strings, objects, arrays,
83
+ * booleans), then numbers by value and strings byte-wise. Sorting the JSON value itself would compare MariaDB's JSON
84
+ * text as text (`"10"` before `"9"`), and MySQL's JSON order puts strings before numbers.
85
+ */
86
+ export function mysqlJsonSortKeys(expr: string, direction: 'ASC' | 'DESC'): string[] {
87
+ const type = `JSON_TYPE(${expr})`;
88
+ return [
89
+ `CASE WHEN ${expr} IS NULL OR ${type} = 'NULL' THEN 0 WHEN ${type} IN ${NUMBER_TYPES} THEN 1 WHEN ${type} = 'STRING' THEN 2 WHEN ${type} = 'OBJECT' THEN 3 WHEN ${type} = 'ARRAY' THEN 4 WHEN ${type} = 'BOOLEAN' THEN 5 ELSE 6 END ${direction}`,
90
+ `${mysqlJsonNumber(expr)} ${direction}`,
91
+ `CASE WHEN ${type} IN ('STRING', 'BOOLEAN') THEN JSON_UNQUOTE(${expr}) END COLLATE utf8mb4_bin ${direction}`,
92
+ ];
93
+ }
94
+
95
+ /** The JSON path of validated segments, as a bound parameter: `$."a"."b"` */
96
+ export function mysqlJsonPath(segments: string[]): string {
97
+ return `$${segments.map((segment) => `."${segment}"`).join('')}`;
98
+ }
99
+
100
+ /**
101
+ * The items of a JSON array as a derived table (`<alias>.v`, `<alias>.<alias>_n` = position from 1). Anything that is
102
+ * not an array has none; `isArray` skips that test for an expression that is one by construction. MySQL reports a JSON
103
+ * `null` item as SQL NULL in `v`; the conditions treat both alike.
104
+ */
105
+ export function mysqlArrayItems(arrayExpr: string, alias: string, isArray = false): string {
106
+ const array = isArray
107
+ ? arrayExpr
108
+ : `CASE WHEN JSON_TYPE(${arrayExpr}) = 'ARRAY' THEN ${arrayExpr} ELSE JSON_ARRAY() END`;
109
+ return `JSON_TABLE(${array}, '$[*]' COLUMNS (${alias}_n FOR ORDINALITY, v JSON PATH '$')) AS ${alias}`;
110
+ }
111
+
112
+ export function compileMysqlWhere(
113
+ variant: MysqlVariant,
114
+ model: ModelDescriptor,
115
+ where: undefined | Where,
116
+ params: SqlParamSink,
117
+ options: MysqlWhereOptions = {},
118
+ ): string {
119
+ return new MysqlWhereCompiler(variant, model, params, options.alias).compile(where);
120
+ }
121
+
122
+ /** The SQL expression of a field path, for ORDER BY and DISTINCT: a column, or a JSON value inside one */
123
+ export function compileMysqlPath(
124
+ variant: MysqlVariant,
125
+ model: ModelDescriptor,
126
+ path: string,
127
+ params: SqlParamSink,
128
+ options: MysqlWhereOptions = {},
129
+ ): { expr: string; field?: FieldDescriptor; kind: 'array' | 'column' | 'json' } {
130
+ const target = new MysqlWhereCompiler(variant, model, params, options.alias).target(path);
131
+ switch (target.kind) {
132
+ case 'array':
133
+ return { expr: target.expr, field: target.element, kind: 'array' };
134
+ case 'column':
135
+ case 'json':
136
+ return { expr: target.expr, field: target.field, kind: target.kind };
137
+ default:
138
+ throw new UnsupportedQueryError(`"${path}" addresses the items of an array`);
139
+ }
140
+ }
141
+
142
+ /**
143
+ * The condition `condition` sets for ONE item (`item`, a JSON expression) of the array field `field`, with `$pull`
144
+ * semantics: an operator object applies to the item, a plain object is a query on an object item's fields, anything
145
+ * else (a scalar, a RegExp) is equality.
146
+ */
147
+ export function compileMysqlItemCondition(
148
+ variant: MysqlVariant,
149
+ model: ModelDescriptor,
150
+ field: string,
151
+ condition: unknown,
152
+ params: SqlParamSink,
153
+ item: string,
154
+ ): string {
155
+ return new MysqlWhereCompiler(variant, model, params).itemCondition(field, condition, item);
156
+ }
157
+
158
+ class MysqlWhereCompiler {
159
+ private items = 0;
160
+
161
+ constructor(
162
+ private readonly variant: MysqlVariant,
163
+ private readonly model: ModelDescriptor,
164
+ private readonly params: SqlParamSink,
165
+ private readonly alias?: string,
166
+ ) {}
167
+
168
+ compile(where: undefined | Where): string {
169
+ return this.conditions(where, (path) => this.resolveField(path));
170
+ }
171
+
172
+ target(path: string): Target {
173
+ return this.resolveField(path);
174
+ }
175
+
176
+ itemCondition(field: string, condition: unknown, item: string): string {
177
+ const target = this.resolveField(field);
178
+ if (target.kind !== 'array') {
179
+ throw new UnsupportedQueryError(`"${field}" is not an array field of ${this.model.name}`);
180
+ }
181
+ if (isOperatorObject(condition)) {
182
+ return this.field(this.itemTarget(target, item), condition);
183
+ }
184
+ const element = target.element;
185
+ if (isPlainObject(condition) && (!element || element.kind === 'object' || element.kind === 'json')) {
186
+ return this.conditions(condition as Where, (path) =>
187
+ this.descend(
188
+ item,
189
+ [],
190
+ element ? { ...element, isArray: false } : undefined,
191
+ splitPath(path),
192
+ `${field}.${path}`,
193
+ ),
194
+ );
195
+ }
196
+ return this.eq(this.itemTarget(target, item), condition);
197
+ }
198
+
199
+ // -- structure ----------------------------------------------------------------------------------------
200
+
201
+ private conditions(where: undefined | Where, resolve: (path: string) => Target): string {
202
+ if (where === undefined || where === null) {
203
+ return 'TRUE';
204
+ }
205
+ if (!isPlainObject(where)) {
206
+ throw new UnsupportedQueryError('A filter must be an object');
207
+ }
208
+ const parts: string[] = [];
209
+ for (const [key, value] of Object.entries(where)) {
210
+ if (key === '$and' || key === '$or' || key === '$nor') {
211
+ if (!Array.isArray(value) || !value.length) {
212
+ throw new UnsupportedQueryError(`${key} needs a non-empty array`);
213
+ }
214
+ const inner = value.map((item) => `(${this.conditions(item, resolve)})`);
215
+ const joined = inner.join(key === '$and' ? ' AND ' : ' OR ');
216
+ parts.push(key === '$nor' ? `NOT COALESCE((${joined}), FALSE)` : `(${joined})`);
217
+ } else if (key === '$comment') {
218
+ continue;
219
+ } else if (key.startsWith('$')) {
220
+ throw new UnsupportedQueryError(`${key} is not supported on SQL`);
221
+ } else {
222
+ parts.push(this.field(resolve(key), value));
223
+ }
224
+ }
225
+ return parts.length ? parts.join(' AND ') : 'TRUE';
226
+ }
227
+
228
+ private field(target: Target, condition: unknown): string {
229
+ if (!isOperatorObject(condition)) {
230
+ return this.eq(target, condition);
231
+ }
232
+ const parts: string[] = [];
233
+ const operators = condition as Record<string, unknown>;
234
+ for (const [operator, value] of Object.entries(operators)) {
235
+ switch (operator) {
236
+ case '$all':
237
+ parts.push(this.all(target, value));
238
+ break;
239
+ case '$elemMatch':
240
+ parts.push(this.elemMatch(target, value));
241
+ break;
242
+ case '$eq':
243
+ if (value instanceof RegExp) {
244
+ throw new UnsupportedQueryError(`$eq with a regular expression at "${target.path}"`);
245
+ }
246
+ parts.push(this.eq(target, value));
247
+ break;
248
+ case '$exists':
249
+ parts.push(this.exists(target, !!value));
250
+ break;
251
+ case '$gt':
252
+ case '$gte':
253
+ case '$lt':
254
+ case '$lte':
255
+ parts.push(this.compare(target, operator, value));
256
+ break;
257
+ case '$in':
258
+ parts.push(this.in(target, value));
259
+ break;
260
+ case '$ne':
261
+ if (value instanceof RegExp) {
262
+ throw new UnsupportedQueryError(`$ne with a regular expression at "${target.path}"`);
263
+ }
264
+ parts.push(`NOT COALESCE(${this.eq(target, value)}, FALSE)`);
265
+ break;
266
+ case '$nin':
267
+ parts.push(`NOT COALESCE(${this.in(target, value)}, FALSE)`);
268
+ break;
269
+ case '$not':
270
+ if (!(value instanceof RegExp) && !isOperatorObject(value)) {
271
+ throw new UnsupportedQueryError(
272
+ `$not needs a regular expression or an operator object at "${target.path}"`,
273
+ );
274
+ }
275
+ parts.push(`NOT COALESCE(${this.field(target, value)}, FALSE)`);
276
+ break;
277
+ case '$options':
278
+ if (!('$regex' in operators)) {
279
+ throw new UnsupportedQueryError(`$options without $regex at "${target.path}"`);
280
+ }
281
+ break;
282
+ case '$regex': {
283
+ if (operators.$options !== undefined && typeof operators.$options !== 'string') {
284
+ throw new UnsupportedQueryError(`$options must be a string at "${target.path}"`);
285
+ }
286
+ const options = operators.$options as string | undefined;
287
+ if (value instanceof RegExp) {
288
+ parts.push(this.regex(target, value.source, options ?? value.flags));
289
+ } else if (typeof value === 'string') {
290
+ parts.push(this.regex(target, value, options ?? ''));
291
+ } else {
292
+ throw new UnsupportedQueryError(`$regex needs a string or a regular expression at "${target.path}"`);
293
+ }
294
+ break;
295
+ }
296
+ case '$size':
297
+ parts.push(this.size(target, value));
298
+ break;
299
+ case '$type':
300
+ parts.push(this.type(target, value));
301
+ break;
302
+ default:
303
+ throw new UnsupportedQueryError(`${operator} is not supported on SQL`);
304
+ }
305
+ }
306
+ return parts.length === 1 ? parts[0] : `(${parts.join(' AND ')})`;
307
+ }
308
+
309
+ // -- paths ----------------------------------------------------------------------------------------------
310
+
311
+ private resolveField(path: string): Target {
312
+ const segments = splitPath(path);
313
+ const [head, ...rest] = segments;
314
+ const name = head === 'id' ? '_id' : head;
315
+ const field = Object.prototype.hasOwnProperty.call(this.model.fields, name) ? this.model.fields[name] : undefined;
316
+ if (!field) {
317
+ throw new UnsupportedQueryError(`Unknown field "${head}" on ${this.model.name}`);
318
+ }
319
+ const column = this.alias
320
+ ? `${quoteMysqlIdentifier(this.alias)}.${quoteMysqlIdentifier(columnName(name))}`
321
+ : quoteMysqlIdentifier(columnName(name));
322
+ if (!rest.length && !field.isArray && SCALAR_KINDS.has(field.kind)) {
323
+ return { expr: column, field, kind: 'column', path };
324
+ }
325
+ return this.descend(column, [], field, rest, path);
326
+ }
327
+
328
+ private descend(
329
+ base: string,
330
+ consumed: string[],
331
+ field: FieldDescriptor | undefined,
332
+ rest: string[],
333
+ path: string,
334
+ ): Target {
335
+ if (!field || field.kind === 'json') {
336
+ if (field?.isArray && rest.length) {
337
+ return this.elements(this.jsonPath(base, consumed), undefined, rest, path);
338
+ }
339
+ if (field?.isArray) {
340
+ return { element: undefined, expr: this.jsonPath(base, consumed), kind: 'array', path };
341
+ }
342
+ return { expr: this.jsonPath(base, [...consumed, ...rest]), kind: 'json', path };
343
+ }
344
+ if (field.isArray) {
345
+ if (!rest.length) {
346
+ return { element: itemOf(field), expr: this.jsonPath(base, consumed), kind: 'array', path };
347
+ }
348
+ if (field.kind !== 'object') {
349
+ throw new UnsupportedQueryError(`"${path}": the items of "${field.name}" have no fields`);
350
+ }
351
+ return this.elements(this.jsonPath(base, consumed), itemOf(field), rest, path);
352
+ }
353
+ if (!rest.length) {
354
+ return { expr: this.jsonPath(base, consumed), field, kind: 'json', path };
355
+ }
356
+ if (field.kind !== 'object') {
357
+ throw new UnsupportedQueryError(`"${path}": "${field.name}" has no fields`);
358
+ }
359
+ const [next, ...more] = rest;
360
+ const nested =
361
+ field.nested && Object.prototype.hasOwnProperty.call(field.nested, next) ? field.nested[next] : undefined;
362
+ if (!nested) {
363
+ throw new UnsupportedQueryError(`Unknown field "${path}" on ${this.model.name}`);
364
+ }
365
+ return this.descend(base, [...consumed, next], nested, more, path);
366
+ }
367
+
368
+ private elements(arrayExpr: string, item: FieldDescriptor | undefined, rest: string[], path: string): Target {
369
+ return {
370
+ arrayExpr,
371
+ inner: (itemExpr) => this.descend(itemExpr, [], item, rest, path),
372
+ kind: 'elements',
373
+ path,
374
+ };
375
+ }
376
+
377
+ /** `base` at `segments`, the path bound as a parameter */
378
+ private jsonPath(base: string, segments: string[]): string {
379
+ return segments.length ? `JSON_EXTRACT(${base}, ${this.params.add(mysqlJsonPath(segments))})` : base;
380
+ }
381
+
382
+ /** Whether ANY item of a JSON array satisfies `condition` — counted, see the file comment on EXISTS */
383
+ private anyItem(arrayExpr: string, condition: (item: string) => string): string {
384
+ const alias = `i${++this.items}`;
385
+ return `((SELECT COUNT(*) FROM ${mysqlArrayItems(arrayExpr, alias)} WHERE ${condition(`${alias}.v`)}) > 0)`;
386
+ }
387
+
388
+ private itemTarget(target: { element?: FieldDescriptor; path: string }, item: string): Target {
389
+ return { expr: item, field: target.element, kind: 'json', path: target.path };
390
+ }
391
+
392
+ // -- operators -------------------------------------------------------------------------------------------
393
+
394
+ private eq(target: Target, value: unknown): string {
395
+ if (value instanceof RegExp) {
396
+ return this.regex(target, value.source, value.flags);
397
+ }
398
+ switch (target.kind) {
399
+ case 'column': {
400
+ const cast = castFilterValue(target.field, target.path, value);
401
+ return cast === null ? `${target.expr} IS NULL` : `${target.expr} = ${this.params.add(cast)}`;
402
+ }
403
+ case 'json': {
404
+ if (value === null || value === undefined) {
405
+ return `(${target.expr} IS NULL OR JSON_TYPE(${target.expr}) = 'NULL')`;
406
+ }
407
+ const equal = this.jsonEquals(target.expr, this.jsonText(target.field, target.path, value));
408
+ if (target.field) {
409
+ return equal;
410
+ }
411
+ // Undeclared content may hold an array, which MongoDB matches by any item
412
+ const item = this.params.add(toJson([this.cast(target.field, target.path, value)]));
413
+ return `(${equal} OR (JSON_TYPE(${target.expr}) = 'ARRAY' AND JSON_CONTAINS(${target.expr}, ${item})))`;
414
+ }
415
+ case 'array': {
416
+ if (value === null || value === undefined) {
417
+ return `(${target.expr} IS NULL OR JSON_TYPE(${target.expr}) = 'NULL' OR JSON_CONTAINS(${target.expr}, 'null'))`;
418
+ }
419
+ if (Array.isArray(value)) {
420
+ const items = value.map((item) => (target.element ? this.castJson(target.element, target.path, item) : item));
421
+ return this.jsonEquals(target.expr, this.params.add(toJson(items)));
422
+ }
423
+ if (isPlainObject(value)) {
424
+ return this.anyItem(target.expr, (item) => this.eq(this.itemTarget(target, item), value));
425
+ }
426
+ const item = target.element ? this.castJson(target.element, target.path, value) : value;
427
+ return `JSON_CONTAINS(${target.expr}, ${this.params.add(toJson([item]))})`;
428
+ }
429
+ case 'elements':
430
+ if (value === null || value === undefined) {
431
+ return `(${target.arrayExpr} IS NULL OR ${this.anyItem(target.arrayExpr, (item) => this.eq(target.inner(item), null))})`;
432
+ }
433
+ return this.anyItem(target.arrayExpr, (item) => this.eq(target.inner(item), value));
434
+ }
435
+ }
436
+
437
+ private compare(target: Target, operator: ComparisonOperator, value: unknown): string {
438
+ if (value === null || value === undefined) {
439
+ throw new UnsupportedQueryError(`${operator} needs a value at "${target.path}"`);
440
+ }
441
+ const sqlOperator = COMPARISON[operator];
442
+ switch (target.kind) {
443
+ case 'column':
444
+ return `${target.expr} ${sqlOperator} ${this.params.add(castFilterValue(target.field, target.path, value))}`;
445
+ case 'json': {
446
+ const cast =
447
+ target.field && SCALAR_KINDS.has(target.field.kind)
448
+ ? castFilterValue(target.field, target.path, value)
449
+ : value;
450
+ // MongoDB compares within one type only; a value of another type never matches. CASE keeps the cast from
451
+ // running on another type — strict mode turns a failed cast in a write's condition into an error
452
+ if (typeof cast === 'number') {
453
+ return `${mysqlJsonNumber(target.expr)} ${sqlOperator} ${this.params.add(cast)}`;
454
+ }
455
+ const text = cast instanceof Date ? cast.toISOString() : cast;
456
+ if (typeof text === 'string') {
457
+ return `(${this.jsonString(target.expr)}) ${sqlOperator} ${this.params.add(text)}`;
458
+ }
459
+ throw new UnsupportedQueryError(`${operator} on "${target.path}" needs a number, a string or a date`);
460
+ }
461
+ case 'array':
462
+ return this.anyItem(target.expr, (item) => this.compare(this.itemTarget(target, item), operator, value));
463
+ case 'elements':
464
+ return this.anyItem(target.arrayExpr, (item) => this.compare(target.inner(item), operator, value));
465
+ }
466
+ }
467
+
468
+ private regex(target: Target, source: string, flags: string): string {
469
+ const pattern = () => this.params.add(`${inlineFlags(target.path, flags)}${source}`);
470
+ switch (target.kind) {
471
+ case 'column':
472
+ if (
473
+ !REGEX_KINDS.has(target.field.kind) ||
474
+ (target.field.kind === 'enum' && target.field.enumBase === 'number')
475
+ ) {
476
+ throw new UnsupportedQueryError(`$regex on the ${target.field.kind} field "${target.path}"`);
477
+ }
478
+ // Byte-wise: case-sensitive unless the pattern says (?i), as on MongoDB — whatever the column's collation
479
+ return `${target.expr} COLLATE utf8mb4_bin REGEXP ${pattern()}`;
480
+ case 'json': {
481
+ const text = `(${this.jsonString(target.expr)}) REGEXP ${pattern()}`;
482
+ if (target.field) {
483
+ return text;
484
+ }
485
+ return `(${text} OR ${this.anyItem(target.expr, (item) => `(${this.jsonString(item)}) REGEXP ${pattern()}`)})`;
486
+ }
487
+ case 'array':
488
+ return this.anyItem(target.expr, (item) => this.regex(this.itemTarget(target, item), source, flags));
489
+ case 'elements':
490
+ return this.anyItem(target.arrayExpr, (item) => this.regex(target.inner(item), source, flags));
491
+ }
492
+ }
493
+
494
+ /** On a column, NULL reads as absent — DIFFERENT-BY-DESIGN from MongoDB's present-but-null, as on PostgreSQL */
495
+ private exists(target: Target, present: boolean): string {
496
+ if (target.kind === 'elements') {
497
+ const any = this.anyItem(target.arrayExpr, (item) => this.exists(target.inner(item), true));
498
+ return present ? any : `NOT ${any}`;
499
+ }
500
+ return `${target.expr} IS ${present ? 'NOT ' : ''}NULL`;
501
+ }
502
+
503
+ private in(target: Target, values: unknown): string {
504
+ if (!Array.isArray(values)) {
505
+ throw new UnsupportedQueryError(`$in / $nin need an array at "${target.path}"`);
506
+ }
507
+ if (!values.length) {
508
+ return 'FALSE';
509
+ }
510
+ if (target.kind !== 'column') {
511
+ return `(${values.map((value) => this.eq(target, value)).join(' OR ')})`;
512
+ }
513
+ const parts: string[] = [];
514
+ const plain: string[] = [];
515
+ let matchesNull = false;
516
+ for (const value of values) {
517
+ if (value instanceof RegExp) {
518
+ parts.push(this.regex(target, value.source, value.flags));
519
+ continue;
520
+ }
521
+ const cast = castFilterValue(target.field, target.path, value);
522
+ if (cast === null) {
523
+ matchesNull = true;
524
+ } else {
525
+ plain.push(this.params.add(cast));
526
+ }
527
+ }
528
+ if (plain.length) {
529
+ parts.unshift(`${target.expr} IN (${plain.join(', ')})`);
530
+ }
531
+ if (matchesNull) {
532
+ parts.push(`${target.expr} IS NULL`);
533
+ }
534
+ return parts.length === 1 ? parts[0] : `(${parts.join(' OR ')})`;
535
+ }
536
+
537
+ private all(target: Target, values: unknown): string {
538
+ if (!Array.isArray(values)) {
539
+ throw new UnsupportedQueryError(`$all needs an array at "${target.path}"`);
540
+ }
541
+ if (!values.length) {
542
+ return 'FALSE';
543
+ }
544
+ return `(${values
545
+ .map((value) => {
546
+ if (isOperatorObject(value)) {
547
+ throw new UnsupportedQueryError(`$all with operators at "${target.path}"`);
548
+ }
549
+ return this.eq(target, value);
550
+ })
551
+ .join(' AND ')})`;
552
+ }
553
+
554
+ private size(target: Target, value: unknown): string {
555
+ const size = typeof value === 'string' && value.trim() !== '' ? Number(value) : value;
556
+ if (typeof size !== 'number' || !Number.isInteger(size) || size < 0) {
557
+ throw new QueryCastError(target.path, 'non-negative integer');
558
+ }
559
+ if (target.kind === 'column') {
560
+ return 'FALSE';
561
+ }
562
+ if (target.kind === 'elements') {
563
+ throw new UnsupportedQueryError(`$size inside array items at "${target.path}"`);
564
+ }
565
+ return `(CASE WHEN JSON_TYPE(${target.expr}) = 'ARRAY' THEN JSON_LENGTH(${target.expr}) END) = ${this.params.add(size)}`;
566
+ }
567
+
568
+ private type(target: Target, value: unknown): string {
569
+ const types = (Array.isArray(value) ? value : [value]).map((item) => bsonType(target.path, item));
570
+ const conditions = types.map((type) => {
571
+ switch (target.kind) {
572
+ case 'column':
573
+ if (type === 'null') {
574
+ return `${target.expr} IS NULL`;
575
+ }
576
+ return COLUMN_TYPES[type]?.(target.field) ? `${target.expr} IS NOT NULL` : 'FALSE';
577
+ case 'json':
578
+ return this.jsonType(target.expr, type, true);
579
+ case 'array':
580
+ return type === 'array'
581
+ ? `JSON_TYPE(${target.expr}) = 'ARRAY'`
582
+ : this.anyItem(target.expr, (item) => this.jsonType(item, type, false));
583
+ case 'elements':
584
+ return this.anyItem(target.arrayExpr, (item) => this.type(target.inner(item), type));
585
+ }
586
+ });
587
+ return conditions.length === 1 ? conditions[0] : `(${conditions.join(' OR ')})`;
588
+ }
589
+
590
+ private jsonType(expr: string, type: BsonType, anyItem: boolean): string {
591
+ const json = JSON_TYPES[type];
592
+ if (!json) {
593
+ throw new UnsupportedQueryError(`$type "${type}" inside JSON`);
594
+ }
595
+ const list = `(${json.map((name) => `'${name}'`).join(', ')})`;
596
+ // MySQL reports a JSON null item of JSON_TABLE as SQL NULL
597
+ const own = type === 'null' ? `(${expr} IS NULL OR JSON_TYPE(${expr}) = 'NULL')` : `JSON_TYPE(${expr}) IN ${list}`;
598
+ if (!anyItem || type === 'array') {
599
+ return own;
600
+ }
601
+ return `(${own} OR ${this.anyItem(expr, (item) => (type === 'null' ? `(${item} IS NULL OR JSON_TYPE(${item}) = 'NULL')` : `JSON_TYPE(${item}) IN ${list}`))})`;
602
+ }
603
+
604
+ private elemMatch(target: Target, condition: unknown): string {
605
+ if (target.kind !== 'array') {
606
+ throw new UnsupportedQueryError(`$elemMatch needs an array at "${target.path}"`);
607
+ }
608
+ if (!isPlainObject(condition)) {
609
+ throw new UnsupportedQueryError(`$elemMatch needs an object at "${target.path}"`);
610
+ }
611
+ const keys = Object.keys(condition);
612
+ const operatorForm =
613
+ keys.length > 0 && keys.every((key) => key.startsWith('$') && !['$and', '$nor', '$or'].includes(key));
614
+ return this.anyItem(target.expr, (item) => {
615
+ if (operatorForm) {
616
+ return this.field(this.itemTarget(target, item), condition);
617
+ }
618
+ const element = target.element;
619
+ if (element && element.kind !== 'object' && element.kind !== 'json') {
620
+ throw new UnsupportedQueryError(`$elemMatch with fields on the scalar items of "${target.path}"`);
621
+ }
622
+ return this.conditions(condition as Where, (path) =>
623
+ this.descend(
624
+ item,
625
+ [],
626
+ element ? { ...element, isArray: false } : undefined,
627
+ splitPath(path),
628
+ `${target.path}.${path}`,
629
+ ),
630
+ );
631
+ });
632
+ }
633
+
634
+ // -- values ----------------------------------------------------------------------------------------------
635
+
636
+ /** A JSON value's text when it is a string, compared byte-wise; NULL for any other type */
637
+ private jsonString(expr: string): string {
638
+ return `CASE WHEN JSON_TYPE(${expr}) = 'STRING' THEN JSON_UNQUOTE(${expr}) END COLLATE utf8mb4_bin`;
639
+ }
640
+
641
+ private jsonEquals(left: string, rightJsonText: string): string {
642
+ return mysqlJsonEquals(this.variant, left, rightJsonText);
643
+ }
644
+
645
+ /** A value as a bound JSON text, cast first when its field is a declared scalar */
646
+ private jsonText(field: FieldDescriptor | undefined, path: string, value: unknown): string {
647
+ return this.params.add(toJson(this.cast(field, path, value)));
648
+ }
649
+
650
+ private cast(field: FieldDescriptor | undefined, path: string, value: unknown): unknown {
651
+ return field ? this.castJson(field, path, value) : value;
652
+ }
653
+
654
+ private castJson(field: FieldDescriptor, path: string, value: unknown): unknown {
655
+ return SCALAR_KINDS.has(field.kind) ? castFilterValue({ ...field, isArray: false }, path, value) : value;
656
+ }
657
+ }
658
+
659
+ /**
660
+ * Regular-expression flags as inline options, understood by MySQL's ICU engine and MariaDB's PCRE2 alike. Both default
661
+ * to MongoDB's behaviour (`.` stops at a newline, `^`/`$` anchor the whole string), so only the given flags are written.
662
+ * `g`, `u`, `y` and `d` do not change whether a string matches.
663
+ */
664
+ function inlineFlags(path: string, flags: string): string {
665
+ let options = '';
666
+ for (const flag of flags) {
667
+ switch (flag) {
668
+ case 'i':
669
+ case 'm':
670
+ case 's':
671
+ case 'x':
672
+ if (!options.includes(flag)) {
673
+ options += flag;
674
+ }
675
+ break;
676
+ case 'd':
677
+ case 'g':
678
+ case 'u':
679
+ case 'y':
680
+ break;
681
+ default:
682
+ throw new UnsupportedQueryError(`Regular-expression option "${flag}" at "${path}"`);
683
+ }
684
+ }
685
+ return options ? `(?${options})` : '';
686
+ }