@rapidrest/service-core 1.0.0-rc.9 → 1.0.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 (380) hide show
  1. package/LICENSE +382 -23
  2. package/README.md +79 -5
  3. package/dist/lib/ApiErrors.js +10 -0
  4. package/dist/lib/ApiErrors.js.map +1 -1
  5. package/dist/lib/BackgroundService.js +1 -4
  6. package/dist/lib/BackgroundService.js.map +1 -1
  7. package/dist/lib/BackgroundServiceManager.js +47 -6
  8. package/dist/lib/BackgroundServiceManager.js.map +1 -1
  9. package/dist/lib/BulkError.js +4 -0
  10. package/dist/lib/BulkError.js.map +1 -1
  11. package/dist/lib/EventListenerManager.js +53 -18
  12. package/dist/lib/EventListenerManager.js.map +1 -1
  13. package/dist/lib/NetUtils.js +1 -0
  14. package/dist/lib/NetUtils.js.map +1 -1
  15. package/dist/lib/NotificationUtils.js +27 -8
  16. package/dist/lib/NotificationUtils.js.map +1 -1
  17. package/dist/lib/ObjectFactory.js +25 -44
  18. package/dist/lib/ObjectFactory.js.map +1 -1
  19. package/dist/lib/OpenApiSpec.js +31 -11
  20. package/dist/lib/OpenApiSpec.js.map +1 -1
  21. package/dist/lib/Server.js +74 -110
  22. package/dist/lib/Server.js.map +1 -1
  23. package/dist/lib/auth/AuthMiddleware.js +11 -16
  24. package/dist/lib/auth/AuthMiddleware.js.map +1 -1
  25. package/dist/lib/auth/JWTStrategy.js +68 -17
  26. package/dist/lib/auth/JWTStrategy.js.map +1 -1
  27. package/dist/lib/auth/index.js +0 -1
  28. package/dist/lib/auth/index.js.map +1 -1
  29. package/dist/lib/database/ConnectionKinds.js +15 -0
  30. package/dist/lib/database/ConnectionKinds.js.map +1 -1
  31. package/dist/lib/database/ConnectionManager.js +140 -61
  32. package/dist/lib/database/ConnectionManager.js.map +1 -1
  33. package/dist/lib/database/MongoConnection.js +13 -3
  34. package/dist/lib/database/MongoConnection.js.map +1 -1
  35. package/dist/lib/database/MongoRepository.js +61 -15
  36. package/dist/lib/database/MongoRepository.js.map +1 -1
  37. package/dist/lib/database/MongoSchemaSync.js +3 -3
  38. package/dist/lib/database/MongoSchemaSync.js.map +1 -1
  39. package/dist/lib/database/NamingUtils.js +3 -2
  40. package/dist/lib/database/NamingUtils.js.map +1 -1
  41. package/dist/lib/database/RedisCache.js +64 -0
  42. package/dist/lib/database/RedisCache.js.map +1 -0
  43. package/dist/lib/database/TypeOrmSupport.js +53 -13
  44. package/dist/lib/database/TypeOrmSupport.js.map +1 -1
  45. package/dist/lib/database/index.js +1 -0
  46. package/dist/lib/database/index.js.map +1 -1
  47. package/dist/lib/decorators/DatabaseDecorators.js +264 -20
  48. package/dist/lib/decorators/DatabaseDecorators.js.map +1 -1
  49. package/dist/lib/decorators/DocDecorators.js +30 -9
  50. package/dist/lib/decorators/DocDecorators.js.map +1 -1
  51. package/dist/lib/decorators/EventDecorators.js +1 -0
  52. package/dist/lib/decorators/EventDecorators.js.map +1 -1
  53. package/dist/lib/decorators/ModelDecorators.js +39 -23
  54. package/dist/lib/decorators/ModelDecorators.js.map +1 -1
  55. package/dist/lib/decorators/PersistenceDecorators.js +4 -3
  56. package/dist/lib/decorators/PersistenceDecorators.js.map +1 -1
  57. package/dist/lib/decorators/RouteDecorators.js +139 -36
  58. package/dist/lib/decorators/RouteDecorators.js.map +1 -1
  59. package/dist/lib/http/IWebSocketShim.js +2 -0
  60. package/dist/lib/http/IWebSocketShim.js.map +1 -0
  61. package/dist/lib/http/MiddlewareChain.js +167 -0
  62. package/dist/lib/http/MiddlewareChain.js.map +1 -0
  63. package/dist/lib/http/RuntimeDetect.js +9 -0
  64. package/dist/lib/http/RuntimeDetect.js.map +1 -0
  65. package/dist/lib/http/bun/BunAdapters.js +326 -0
  66. package/dist/lib/http/bun/BunAdapters.js.map +1 -0
  67. package/dist/lib/http/bun/BunRouter.js +391 -0
  68. package/dist/lib/http/bun/BunRouter.js.map +1 -0
  69. package/dist/lib/http/bun/BunWebSocket.js +49 -0
  70. package/dist/lib/http/bun/BunWebSocket.js.map +1 -0
  71. package/dist/lib/http/index.js +16 -3
  72. package/dist/lib/http/index.js.map +1 -1
  73. package/dist/lib/http/session/RedisSessionStore.js +30 -0
  74. package/dist/lib/http/session/RedisSessionStore.js.map +1 -0
  75. package/dist/lib/http/session/SessionManager.js +113 -0
  76. package/dist/lib/http/session/SessionManager.js.map +1 -0
  77. package/dist/lib/http/session/SessionStore.js +6 -0
  78. package/dist/lib/http/session/SessionStore.js.map +1 -0
  79. package/dist/lib/http/session/sessionMiddleware.js +42 -0
  80. package/dist/lib/http/session/sessionMiddleware.js.map +1 -0
  81. package/dist/lib/http/types.js +0 -3
  82. package/dist/lib/http/types.js.map +1 -1
  83. package/dist/lib/http/uWS/Adapters.js +421 -0
  84. package/dist/lib/http/uWS/Adapters.js.map +1 -0
  85. package/dist/lib/http/{Router.js → uWS/Router.js} +73 -173
  86. package/dist/lib/http/uWS/Router.js.map +1 -0
  87. package/dist/lib/http/{WebSocket.js → uWS/WebSocket.js} +4 -1
  88. package/dist/lib/http/uWS/WebSocket.js.map +1 -0
  89. package/dist/lib/models/BaseEntity.js +2 -1
  90. package/dist/lib/models/BaseEntity.js.map +1 -1
  91. package/dist/lib/models/BaseMongoEntity.js +2 -2
  92. package/dist/lib/models/BaseMongoEntity.js.map +1 -1
  93. package/dist/lib/models/ModelUtils.js +248 -101
  94. package/dist/lib/models/ModelUtils.js.map +1 -1
  95. package/dist/lib/models/RecoverableBaseEntity.js +6 -1
  96. package/dist/lib/models/RecoverableBaseEntity.js.map +1 -1
  97. package/dist/lib/models/RecoverableBaseMongoEntity.js +1 -0
  98. package/dist/lib/models/RecoverableBaseMongoEntity.js.map +1 -1
  99. package/dist/lib/models/RepoUtils.js +641 -213
  100. package/dist/lib/models/RepoUtils.js.map +1 -1
  101. package/dist/lib/models/SimpleEntity.js +1 -0
  102. package/dist/lib/models/SimpleEntity.js.map +1 -1
  103. package/dist/lib/models/SimpleMongoEntity.js +2 -1
  104. package/dist/lib/models/SimpleMongoEntity.js.map +1 -1
  105. package/dist/lib/models/StatusExtraData.js +4 -0
  106. package/dist/lib/models/StatusExtraData.js.map +1 -1
  107. package/dist/lib/routes/{AdminRoute.js → BaseAdminRoute.js} +98 -80
  108. package/dist/lib/routes/BaseAdminRoute.js.map +1 -0
  109. package/dist/lib/routes/{MetricsRoute.js → BaseMetricsRoute.js} +29 -15
  110. package/dist/lib/routes/BaseMetricsRoute.js.map +1 -0
  111. package/dist/lib/routes/{OpenAPIRoute.js → BaseOpenAPIRoute.js} +32 -32
  112. package/dist/lib/routes/BaseOpenAPIRoute.js.map +1 -0
  113. package/dist/lib/routes/BasePushRoute.js +305 -0
  114. package/dist/lib/routes/BasePushRoute.js.map +1 -0
  115. package/dist/lib/routes/BaseStaticRoute.js +153 -0
  116. package/dist/lib/routes/BaseStaticRoute.js.map +1 -0
  117. package/dist/lib/routes/BaseStatusRoute.js +80 -0
  118. package/dist/lib/routes/BaseStatusRoute.js.map +1 -0
  119. package/dist/lib/routes/CRUDRoute.js +284 -0
  120. package/dist/lib/routes/CRUDRoute.js.map +1 -0
  121. package/dist/lib/routes/ModelRoute.js +84 -57
  122. package/dist/lib/routes/ModelRoute.js.map +1 -1
  123. package/dist/lib/routes/RouteUtils.js +108 -20
  124. package/dist/lib/routes/RouteUtils.js.map +1 -1
  125. package/dist/lib/routes/index.js +7 -4
  126. package/dist/lib/routes/index.js.map +1 -1
  127. package/dist/lib/security/ACLUtils.js +297 -170
  128. package/dist/lib/security/ACLUtils.js.map +1 -1
  129. package/dist/lib/security/AccessControlList.js +18 -10
  130. package/dist/lib/security/AccessControlList.js.map +1 -1
  131. package/dist/lib/security/AccessControlListMongo.js +19 -68
  132. package/dist/lib/security/AccessControlListMongo.js.map +1 -1
  133. package/dist/lib/security/AccessControlListSQL.js +21 -70
  134. package/dist/lib/security/AccessControlListSQL.js.map +1 -1
  135. package/dist/lib/security/BaseACLRoute.js +239 -0
  136. package/dist/lib/security/BaseACLRoute.js.map +1 -0
  137. package/dist/lib/security/index.js +3 -0
  138. package/dist/lib/security/index.js.map +1 -1
  139. package/dist/lib/test/request.js +62 -5
  140. package/dist/lib/test/request.js.map +1 -1
  141. package/dist/lib/test/requestws.js +34 -10
  142. package/dist/lib/test/requestws.js.map +1 -1
  143. package/dist/types/ApiErrors.d.ts +8 -2
  144. package/dist/types/BackgroundService.d.ts +0 -5
  145. package/dist/types/BackgroundServiceManager.d.ts +2 -1
  146. package/dist/types/EventListenerManager.d.ts +7 -6
  147. package/dist/types/NotificationUtils.d.ts +5 -3
  148. package/dist/types/OpenApiSpec.d.ts +2 -2
  149. package/dist/types/Server.d.ts +28 -10
  150. package/dist/types/auth/AuthMiddleware.d.ts +3 -3
  151. package/dist/types/auth/AuthStrategy.d.ts +10 -7
  152. package/dist/types/auth/JWTStrategy.d.ts +6 -4
  153. package/dist/types/auth/index.d.ts +0 -1
  154. package/dist/types/database/ConnectionKinds.d.ts +7 -0
  155. package/dist/types/database/ConnectionManager.d.ts +29 -4
  156. package/dist/types/database/MongoConnection.d.ts +16 -4
  157. package/dist/types/database/MongoRepository.d.ts +32 -11
  158. package/dist/types/database/RedisCache.d.ts +23 -0
  159. package/dist/types/database/TypeOrmSupport.d.ts +4 -4
  160. package/dist/types/database/index.d.ts +1 -0
  161. package/dist/types/decorators/DatabaseDecorators.d.ts +139 -8
  162. package/dist/types/decorators/DocDecorators.d.ts +11 -2
  163. package/dist/types/decorators/ModelDecorators.d.ts +12 -5
  164. package/dist/types/decorators/PersistenceDecorators.d.ts +11 -4
  165. package/dist/types/decorators/RouteDecorators.d.ts +36 -6
  166. package/dist/types/http/IWebSocketShim.d.ts +11 -0
  167. package/dist/types/http/MiddlewareChain.d.ts +47 -0
  168. package/dist/types/http/RuntimeDetect.d.ts +2 -0
  169. package/dist/types/http/bun/BunAdapters.d.ts +139 -0
  170. package/dist/types/http/bun/BunRouter.d.ts +79 -0
  171. package/dist/types/http/bun/BunWebSocket.d.ts +35 -0
  172. package/dist/types/http/index.d.ts +16 -6
  173. package/dist/types/http/session/RedisSessionStore.d.ts +15 -0
  174. package/dist/types/http/session/SessionManager.d.ts +35 -0
  175. package/dist/types/http/session/SessionStore.d.ts +12 -0
  176. package/dist/types/http/session/sessionMiddleware.d.ts +10 -0
  177. package/dist/types/http/types.d.ts +42 -3
  178. package/dist/types/http/uWS/Adapters.d.ts +129 -0
  179. package/dist/types/http/{Router.d.ts → uWS/Router.d.ts} +14 -38
  180. package/dist/types/http/{WebSocket.d.ts → uWS/WebSocket.d.ts} +6 -5
  181. package/dist/types/models/BaseEntity.d.ts +1 -1
  182. package/dist/types/models/ModelUtils.d.ts +47 -14
  183. package/dist/types/models/RecoverableBaseEntity.d.ts +3 -1
  184. package/dist/types/models/RepoUtils.d.ts +84 -14
  185. package/dist/types/routes/BaseAdminRoute.d.ts +65 -0
  186. package/dist/types/routes/BaseMetricsRoute.d.ts +37 -0
  187. package/dist/types/routes/BaseOpenAPIRoute.d.ts +33 -0
  188. package/dist/types/routes/BasePushRoute.d.ts +53 -0
  189. package/dist/types/routes/BaseStaticRoute.d.ts +44 -0
  190. package/dist/types/routes/BaseStatusRoute.d.ts +37 -0
  191. package/dist/types/routes/CRUDRoute.d.ts +57 -0
  192. package/dist/types/routes/ModelRoute.d.ts +39 -36
  193. package/dist/types/routes/RouteUtils.d.ts +19 -0
  194. package/dist/types/routes/index.d.ts +7 -4
  195. package/dist/types/security/ACLUtils.d.ts +94 -18
  196. package/dist/types/security/AccessControlList.d.ts +37 -59
  197. package/dist/types/security/AccessControlListMongo.d.ts +3 -8
  198. package/dist/types/security/AccessControlListSQL.d.ts +3 -8
  199. package/dist/types/security/BaseACLRoute.d.ts +73 -0
  200. package/dist/types/security/index.d.ts +3 -0
  201. package/dist/types/test/request.d.ts +18 -1
  202. package/package.json +135 -129
  203. package/tsconfig.export.json +17 -0
  204. package/dist/lib/auth/BasicStrategy.js +0 -113
  205. package/dist/lib/auth/BasicStrategy.js.map +0 -1
  206. package/dist/lib/http/Adapters.js +0 -241
  207. package/dist/lib/http/Adapters.js.map +0 -1
  208. package/dist/lib/http/Router.js.map +0 -1
  209. package/dist/lib/http/WebSocket.js.map +0 -1
  210. package/dist/lib/routes/AdminRoute.js.map +0 -1
  211. package/dist/lib/routes/MetricsRoute.js.map +0 -1
  212. package/dist/lib/routes/OpenAPIRoute.js.map +0 -1
  213. package/dist/lib/routes/StatusRoute.js +0 -55
  214. package/dist/lib/routes/StatusRoute.js.map +0 -1
  215. package/dist/lib/security/ACLRouteMongo.js +0 -194
  216. package/dist/lib/security/ACLRouteMongo.js.map +0 -1
  217. package/dist/lib/security/ACLRouteSQL.js +0 -193
  218. package/dist/lib/security/ACLRouteSQL.js.map +0 -1
  219. package/dist/types/auth/BasicStrategy.d.ts +0 -37
  220. package/dist/types/http/Adapters.d.ts +0 -68
  221. package/dist/types/routes/AdminRoute.d.ts +0 -47
  222. package/dist/types/routes/MetricsRoute.d.ts +0 -15
  223. package/dist/types/routes/OpenAPIRoute.d.ts +0 -17
  224. package/dist/types/routes/StatusRoute.d.ts +0 -11
  225. package/dist/types/security/ACLRouteMongo.d.ts +0 -19
  226. package/dist/types/security/ACLRouteSQL.d.ts +0 -19
  227. package/docs/Makefile +0 -20
  228. package/docs/conf.py +0 -58
  229. package/docs/index.rst +0 -17
  230. package/docs/make.bat +0 -35
  231. package/docs/reference/@rapidrest/namespaces/DatabaseDecorators/README.md +0 -13
  232. package/docs/reference/@rapidrest/namespaces/DatabaseDecorators/functions/MongoRepository.md +0 -25
  233. package/docs/reference/@rapidrest/namespaces/DatabaseDecorators/functions/RedisConnection.md +0 -25
  234. package/docs/reference/@rapidrest/namespaces/DatabaseDecorators/functions/Repository.md +0 -25
  235. package/docs/reference/@rapidrest/namespaces/DocDecorators/README.md +0 -23
  236. package/docs/reference/@rapidrest/namespaces/DocDecorators/functions/Default.md +0 -25
  237. package/docs/reference/@rapidrest/namespaces/DocDecorators/functions/Description.md +0 -25
  238. package/docs/reference/@rapidrest/namespaces/DocDecorators/functions/Document.md +0 -25
  239. package/docs/reference/@rapidrest/namespaces/DocDecorators/functions/Example.md +0 -25
  240. package/docs/reference/@rapidrest/namespaces/DocDecorators/functions/Format.md +0 -25
  241. package/docs/reference/@rapidrest/namespaces/DocDecorators/functions/Returns.md +0 -28
  242. package/docs/reference/@rapidrest/namespaces/DocDecorators/functions/Summary.md +0 -25
  243. package/docs/reference/@rapidrest/namespaces/DocDecorators/functions/Tags.md +0 -25
  244. package/docs/reference/@rapidrest/namespaces/DocDecorators/functions/TypeInfo.md +0 -28
  245. package/docs/reference/@rapidrest/namespaces/DocDecorators/interfaces/DocumentsData.md +0 -57
  246. package/docs/reference/@rapidrest/namespaces/EventDecorators/README.md +0 -12
  247. package/docs/reference/@rapidrest/namespaces/EventDecorators/functions/EventListener.md +0 -17
  248. package/docs/reference/@rapidrest/namespaces/EventDecorators/functions/OnEvent.md +0 -26
  249. package/docs/reference/@rapidrest/namespaces/ModelDecorators/README.md +0 -26
  250. package/docs/reference/@rapidrest/namespaces/ModelDecorators/functions/Cache.md +0 -25
  251. package/docs/reference/@rapidrest/namespaces/ModelDecorators/functions/ChildEntity.md +0 -18
  252. package/docs/reference/@rapidrest/namespaces/ModelDecorators/functions/DataStore.md +0 -25
  253. package/docs/reference/@rapidrest/namespaces/ModelDecorators/functions/Identifier.md +0 -27
  254. package/docs/reference/@rapidrest/namespaces/ModelDecorators/functions/Protect.md +0 -35
  255. package/docs/reference/@rapidrest/namespaces/ModelDecorators/functions/Reference.md +0 -25
  256. package/docs/reference/@rapidrest/namespaces/ModelDecorators/functions/Shard.md +0 -27
  257. package/docs/reference/@rapidrest/namespaces/ModelDecorators/functions/TrackChanges.md +0 -26
  258. package/docs/reference/@rapidrest/namespaces/ModelDecorators/interfaces/PendingTypeOrmColumn.md +0 -45
  259. package/docs/reference/@rapidrest/namespaces/ModelDecorators/variables/pendingTypeOrmColumns.md +0 -14
  260. package/docs/reference/@rapidrest/namespaces/PersistenceDecorators/README.md +0 -27
  261. package/docs/reference/@rapidrest/namespaces/PersistenceDecorators/functions/Column.md +0 -25
  262. package/docs/reference/@rapidrest/namespaces/PersistenceDecorators/functions/Entity.md +0 -25
  263. package/docs/reference/@rapidrest/namespaces/PersistenceDecorators/functions/Index.md +0 -119
  264. package/docs/reference/@rapidrest/namespaces/PersistenceDecorators/functions/PrimaryColumn.md +0 -25
  265. package/docs/reference/@rapidrest/namespaces/PersistenceDecorators/functions/Unique.md +0 -68
  266. package/docs/reference/@rapidrest/namespaces/PersistenceDecorators/functions/getColumnMetadata.md +0 -26
  267. package/docs/reference/@rapidrest/namespaces/PersistenceDecorators/functions/getEntityName.md +0 -26
  268. package/docs/reference/@rapidrest/namespaces/PersistenceDecorators/functions/getIndexMetadata.md +0 -27
  269. package/docs/reference/@rapidrest/namespaces/PersistenceDecorators/interfaces/CollationOptions.md +0 -79
  270. package/docs/reference/@rapidrest/namespaces/PersistenceDecorators/interfaces/ColumnInfo.md +0 -41
  271. package/docs/reference/@rapidrest/namespaces/PersistenceDecorators/interfaces/ColumnOptions.md +0 -51
  272. package/docs/reference/@rapidrest/namespaces/PersistenceDecorators/interfaces/EntityOptions.md +0 -32
  273. package/docs/reference/@rapidrest/namespaces/PersistenceDecorators/interfaces/IndexInfo.md +0 -41
  274. package/docs/reference/@rapidrest/namespaces/PersistenceDecorators/interfaces/IndexOptions.md +0 -61
  275. package/docs/reference/@rapidrest/namespaces/RouteDecorators/README.md +0 -36
  276. package/docs/reference/@rapidrest/namespaces/RouteDecorators/functions/After.md +0 -26
  277. package/docs/reference/@rapidrest/namespaces/RouteDecorators/functions/Auth.md +0 -33
  278. package/docs/reference/@rapidrest/namespaces/RouteDecorators/functions/AuthResult.md +0 -31
  279. package/docs/reference/@rapidrest/namespaces/RouteDecorators/functions/Before.md +0 -25
  280. package/docs/reference/@rapidrest/namespaces/RouteDecorators/functions/ContentType.md +0 -25
  281. package/docs/reference/@rapidrest/namespaces/RouteDecorators/functions/Delete.md +0 -25
  282. package/docs/reference/@rapidrest/namespaces/RouteDecorators/functions/Get.md +0 -25
  283. package/docs/reference/@rapidrest/namespaces/RouteDecorators/functions/Head.md +0 -25
  284. package/docs/reference/@rapidrest/namespaces/RouteDecorators/functions/Header.md +0 -25
  285. package/docs/reference/@rapidrest/namespaces/RouteDecorators/functions/Method.md +0 -31
  286. package/docs/reference/@rapidrest/namespaces/RouteDecorators/functions/Model.md +0 -25
  287. package/docs/reference/@rapidrest/namespaces/RouteDecorators/functions/Options.md +0 -25
  288. package/docs/reference/@rapidrest/namespaces/RouteDecorators/functions/Param.md +0 -26
  289. package/docs/reference/@rapidrest/namespaces/RouteDecorators/functions/Patch.md +0 -25
  290. package/docs/reference/@rapidrest/namespaces/RouteDecorators/functions/Post.md +0 -25
  291. package/docs/reference/@rapidrest/namespaces/RouteDecorators/functions/Protect.md +0 -31
  292. package/docs/reference/@rapidrest/namespaces/RouteDecorators/functions/Put.md +0 -25
  293. package/docs/reference/@rapidrest/namespaces/RouteDecorators/functions/Query.md +0 -26
  294. package/docs/reference/@rapidrest/namespaces/RouteDecorators/functions/Request.md +0 -31
  295. package/docs/reference/@rapidrest/namespaces/RouteDecorators/functions/RequiresRole.md +0 -26
  296. package/docs/reference/@rapidrest/namespaces/RouteDecorators/functions/Response.md +0 -31
  297. package/docs/reference/@rapidrest/namespaces/RouteDecorators/functions/Route.md +0 -25
  298. package/docs/reference/@rapidrest/namespaces/RouteDecorators/functions/Socket.md +0 -33
  299. package/docs/reference/@rapidrest/namespaces/RouteDecorators/functions/User.md +0 -31
  300. package/docs/reference/@rapidrest/namespaces/RouteDecorators/functions/Validate.md +0 -25
  301. package/docs/reference/@rapidrest/namespaces/RouteDecorators/functions/WebSocket.md +0 -25
  302. package/docs/reference/README.md +0 -20
  303. package/docs/reference/classes/ACLUtils.md +0 -263
  304. package/docs/reference/classes/AdminRoute.md +0 -51
  305. package/docs/reference/classes/AuthMiddleware.md +0 -173
  306. package/docs/reference/classes/BackgroundService.md +0 -117
  307. package/docs/reference/classes/BackgroundServiceManager.md +0 -172
  308. package/docs/reference/classes/BaseEntity.md +0 -82
  309. package/docs/reference/classes/BaseMongoEntity.md +0 -107
  310. package/docs/reference/classes/BasicStrategy.md +0 -131
  311. package/docs/reference/classes/BasicStrategyOptions.md +0 -115
  312. package/docs/reference/classes/BulkError.md +0 -271
  313. package/docs/reference/classes/ConnectionManager.md +0 -75
  314. package/docs/reference/classes/EventListenerManager.md +0 -88
  315. package/docs/reference/classes/HttpRouter.md +0 -343
  316. package/docs/reference/classes/JWTStrategy.md +0 -100
  317. package/docs/reference/classes/JWTStrategyOptions.md +0 -97
  318. package/docs/reference/classes/MetricsRoute.md +0 -27
  319. package/docs/reference/classes/ModelRoute.md +0 -527
  320. package/docs/reference/classes/ModelUtils.md +0 -446
  321. package/docs/reference/classes/MongoConnection.md +0 -218
  322. package/docs/reference/classes/MongoRepository.md +0 -390
  323. package/docs/reference/classes/MongoSchemaSync.md +0 -97
  324. package/docs/reference/classes/NetUtils.md +0 -90
  325. package/docs/reference/classes/NotificationUtils.md +0 -77
  326. package/docs/reference/classes/ObjectFactory.md +0 -336
  327. package/docs/reference/classes/OpenAPIRoute.md +0 -77
  328. package/docs/reference/classes/OpenApiSpec.md +0 -892
  329. package/docs/reference/classes/RecoverableBaseEntity.md +0 -114
  330. package/docs/reference/classes/RecoverableBaseMongoEntity.md +0 -124
  331. package/docs/reference/classes/RedisTransport.md +0 -2202
  332. package/docs/reference/classes/RepoUtils.md +0 -482
  333. package/docs/reference/classes/RouteUtils.md +0 -191
  334. package/docs/reference/classes/Server.md +0 -408
  335. package/docs/reference/classes/SimpleEntity.md +0 -48
  336. package/docs/reference/classes/SimpleMongoEntity.md +0 -66
  337. package/docs/reference/classes/StatusExtraData.md +0 -57
  338. package/docs/reference/classes/StatusRoute.md +0 -26
  339. package/docs/reference/classes/UWSRequest.md +0 -226
  340. package/docs/reference/classes/UWSResponse.md +0 -257
  341. package/docs/reference/classes/UWSWebSocketShim.md +0 -958
  342. package/docs/reference/enumerations/ACLAction.md +0 -63
  343. package/docs/reference/enumerations/ApiErrorMessages.md +0 -123
  344. package/docs/reference/enumerations/ApiErrors.md +0 -123
  345. package/docs/reference/functions/createWebSocketStream.md +0 -27
  346. package/docs/reference/functions/isSqlDataSource.md +0 -26
  347. package/docs/reference/functions/readBody.md +0 -29
  348. package/docs/reference/functions/resolveCollectionName.md +0 -33
  349. package/docs/reference/functions/runChain.md +0 -40
  350. package/docs/reference/functions/snakeCase.md +0 -28
  351. package/docs/reference/globals.md +0 -106
  352. package/docs/reference/interfaces/ACLRecord.md +0 -96
  353. package/docs/reference/interfaces/AccessControlList.md +0 -76
  354. package/docs/reference/interfaces/AuthResult.md +0 -55
  355. package/docs/reference/interfaces/AuthStrategy.md +0 -95
  356. package/docs/reference/interfaces/CreateRequestOptions.md +0 -121
  357. package/docs/reference/interfaces/DeleteRequestOptions.md +0 -137
  358. package/docs/reference/interfaces/FindRequestOptions.md +0 -133
  359. package/docs/reference/interfaces/HttpRequest.md +0 -147
  360. package/docs/reference/interfaces/HttpResponse.md +0 -164
  361. package/docs/reference/interfaces/JWTAuthResult.md +0 -84
  362. package/docs/reference/interfaces/RepoCreateOptions.md +0 -95
  363. package/docs/reference/interfaces/RepoDeleteOptions.md +0 -105
  364. package/docs/reference/interfaces/RepoFindOptions.md +0 -125
  365. package/docs/reference/interfaces/RepoOperationOptions.md +0 -69
  366. package/docs/reference/interfaces/RepoUpdateOptions.md +0 -101
  367. package/docs/reference/interfaces/RequestOptions.md +0 -112
  368. package/docs/reference/interfaces/RequestWS.md +0 -225
  369. package/docs/reference/interfaces/TruncateRequestOptions.md +0 -161
  370. package/docs/reference/interfaces/UpdateRequestOptions.md +0 -139
  371. package/docs/reference/type-aliases/ErrorHandler.md +0 -35
  372. package/docs/reference/type-aliases/NextFunction.md +0 -23
  373. package/docs/reference/type-aliases/OneOrMany.md +0 -19
  374. package/docs/reference/type-aliases/OneOrNull.md +0 -19
  375. package/docs/reference/type-aliases/PartialBaseEntity.md +0 -17
  376. package/docs/reference/type-aliases/PartialSimpleEntity.md +0 -17
  377. package/docs/reference/type-aliases/RequestHandler.md +0 -31
  378. package/docs/reference/type-aliases/UpdateObject.md +0 -19
  379. package/docs/reference/type-aliases/WsUpgradeAuth.md +0 -27
  380. package/docs/reference/type-aliases/WsUpgradeAuthResult.md +0 -47
@@ -6,8 +6,10 @@ import { RecoverableBaseEntity } from "./RecoverableBaseEntity.js";
6
6
  import { ApiErrorMessages, ApiErrors } from "../ApiErrors.js";
7
7
  const logger = Logger();
8
8
  const REGEX_QUERY_PARAM_VALUE = new RegExp(/^([a-zA-Z]+)\((.*)\)$/, "i");
9
- const REGEX_RESERVED_QUERY_PARAMS = new RegExp("(jwt_|oauth_|auth_|cache).*", "i");
10
- const REGEX_QUERY_LIMITS = new RegExp("(limit|page|sort).*", "i");
9
+ // Anchored at the start so these only match the intended reserved parameter names/prefixes and not any
10
+ // field that merely contains one as a substring (e.g. "sortOrder", "rateLimit", "packageId", "homepage").
11
+ const REGEX_RESERVED_QUERY_PARAMS = new RegExp("^(jwt_|oauth_|auth_|cache).*", "i");
12
+ const REGEX_QUERY_LIMITS = new RegExp("^(limit|page|sort)$", "i");
11
13
  const REGEX_QUERY_SORT_STRING = new RegExp(/^\{.*\}$/, "i");
12
14
  // Apparently calling JSON.stringify on RegExp returns an empty set. So the recommended way to
13
15
  // overcome this is by adding a `toJSON` method that uses the `toString` instead which will
@@ -21,7 +23,7 @@ RegExp.prototype.toJSON = RegExp.prototype.toString;
21
23
  export class ModelUtils {
22
24
  /**
23
25
  * Provides the `typeorm` module to use when building SQL queries. This is called automatically when a SQL
24
- * datastore connection is established.
26
+ * datasource connection is established.
25
27
  *
26
28
  * @param module The `typeorm` module.
27
29
  */
@@ -33,7 +35,7 @@ export class ModelUtils {
33
35
  */
34
36
  static get orm() {
35
37
  if (!ModelUtils.typeOrm) {
36
- throw new Error("SQL query construction requires the optional peer dependency 'typeorm' but no SQL datastore has been initialized.");
38
+ throw new Error("SQL query construction requires the optional peer dependency 'typeorm' but no SQL datasource has been initialized.");
37
39
  }
38
40
  return ModelUtils.typeOrm;
39
41
  }
@@ -65,6 +67,34 @@ export class ModelUtils {
65
67
  ModelUtils.idPropertyCache.set(modelClass, results);
66
68
  return results;
67
69
  }
70
+ /**
71
+ * Retrieves a list of all of the specified class's properties that have the @ReadOnly decorator applied.
72
+ *
73
+ * @param modelClass The class definition to search for read-only properties from.
74
+ * @returns The list of all property names that have the @ReadOnly decorator applied.
75
+ */
76
+ static getReadOnlyPropertyNames(modelClass) {
77
+ const results = [];
78
+ if (ModelUtils.readOnlyPropertyCache.has(modelClass)) {
79
+ return ModelUtils.readOnlyPropertyCache.get(modelClass);
80
+ }
81
+ // The props don't show up correctly on the class def. So instantiate a dummy object that we can read the props
82
+ // from and look for read-only fields.
83
+ let proto = Object.getPrototypeOf(new modelClass());
84
+ while (proto) {
85
+ const props = Object.getOwnPropertyNames(proto);
86
+ for (const prop of props) {
87
+ const isReadOnly = Reflect.getMetadata("rrst:readOnly", proto, prop);
88
+ if (isReadOnly) {
89
+ results.push(prop);
90
+ }
91
+ }
92
+ proto = Object.getPrototypeOf(proto);
93
+ }
94
+ // Cache the results so we're not always having to walk the class structure
95
+ ModelUtils.readOnlyPropertyCache.set(modelClass, results);
96
+ return results;
97
+ }
68
98
  /**
69
99
  * Builds a query object for use with `find` functions of the given repository for retrieving objects matching the
70
100
  * specified unique identifier.
@@ -73,14 +103,19 @@ export class ModelUtils {
73
103
  * @param modelClass The class definition of the data model to build a search query for.
74
104
  * @param id The unique identifier to search for.
75
105
  * @param version The version number of the document to search for.
106
+ * @param includeDeleted Set to false to exclude soft-deleted `RecoverableBaseEntity` records from matching.
107
+ * Defaults to true (matches regardless of deleted state) to preserve existing lookup/validation behavior;
108
+ * callers that expose a record by id to an API client (e.g. `findOne`, `exists`) should pass false so a
109
+ * soft-deleted record doesn't remain fully readable/resurrectable, the same way `buildSearchQuery` already
110
+ * excludes deleted records by default for list-style queries.
76
111
  * @returns An object that can be passed to a TypeORM `find` function.
77
112
  */
78
- static buildIdSearchQuery(repo, modelClass, id, version) {
113
+ static buildIdSearchQuery(repo, modelClass, id, version, includeDeleted = true) {
79
114
  if (repo instanceof MongoRepository) {
80
- return ModelUtils.buildIdSearchQueryMongo(modelClass, id, version);
115
+ return ModelUtils.buildIdSearchQueryMongo(modelClass, id, version, includeDeleted);
81
116
  }
82
117
  else {
83
- return ModelUtils.buildIdSearchQuerySQL(modelClass, id, version);
118
+ return ModelUtils.buildIdSearchQuerySQL(modelClass, id, version, includeDeleted);
84
119
  }
85
120
  }
86
121
  /**
@@ -92,8 +127,9 @@ export class ModelUtils {
92
127
  * @param version The version number of the document to search for.
93
128
  * @returns An object that can be passed to a TypeORM `find` function.
94
129
  */
95
- static buildIdSearchQuerySQL(modelClass, id, version) {
130
+ static buildIdSearchQuerySQL(modelClass, id, version, includeDeleted = true) {
96
131
  const props = ModelUtils.getIdPropertyNames(modelClass);
132
+ const isRecoverable = new modelClass() instanceof RecoverableBaseEntity;
97
133
  // Create the where in SQL syntax. We only care about one of the identifier field's matching.
98
134
  // e.g. WHERE idField1 = :idField1 OR idField2 = :idField2 ...
99
135
  const where = [];
@@ -102,6 +138,11 @@ export class ModelUtils {
102
138
  if (version !== undefined) {
103
139
  q.version = version;
104
140
  }
141
+ // By default we don't want an id-based lookup to match a soft-deleted recoverable object,
142
+ // matching the same default `buildSearchQuery` applies to list-style queries.
143
+ if (isRecoverable && !includeDeleted) {
144
+ q.deleted = false;
145
+ }
105
146
  where.push(q);
106
147
  }
107
148
  return { where };
@@ -113,10 +154,12 @@ export class ModelUtils {
113
154
  * @param modelClass The class definition of the data model to build a search query for.
114
155
  * @param id The unique identifier to search for.
115
156
  * @param version The version number of the document to search for.
157
+ * @param includeDeleted Set to true to also match soft-deleted `RecoverableBaseEntity` records.
116
158
  * @returns An object that can be passed to a MongoDB `find` function.
117
159
  */
118
- static buildIdSearchQueryMongo(modelClass, id, version) {
160
+ static buildIdSearchQueryMongo(modelClass, id, version, includeDeleted = true) {
119
161
  const props = ModelUtils.getIdPropertyNames(modelClass);
162
+ const isRecoverable = new modelClass() instanceof RecoverableBaseEntity;
120
163
  // We want to performa case-insensitive search. We used to convert strings to RegEx but this is _very_
121
164
  // slow. Instead, we use case-insenstive indexes that are configured using the `collation` option. Now
122
165
  // we only need to pass in the raw string. So we skip this section but we retain the code for historical
@@ -138,6 +181,11 @@ export class ModelUtils {
138
181
  if (version !== undefined) {
139
182
  q.version = version;
140
183
  }
184
+ // By default we don't want an id-based lookup to match a soft-deleted recoverable object,
185
+ // matching the same default `buildSearchQuery` applies to list-style queries.
186
+ if (isRecoverable && !includeDeleted) {
187
+ q.deleted = false;
188
+ }
141
189
  query.push(q);
142
190
  }
143
191
  return { $or: query };
@@ -179,7 +227,9 @@ export class ModelUtils {
179
227
  case "gte":
180
228
  return MoreThanOrEqual(value);
181
229
  case "in": {
182
- const args = value.split(",");
230
+ // Split the raw match text, not `value`: a comma-joined list like "1,5" can itself parse
231
+ // as a valid `Date` above (e.g. "1,5" -> Jan 5), leaving `value` a Date with no `.split()`.
232
+ const args = matches[2].split(",");
183
233
  return In(args);
184
234
  }
185
235
  case "like":
@@ -191,8 +241,14 @@ export class ModelUtils {
191
241
  case "ne":
192
242
  case "not":
193
243
  return Not(value);
244
+ case "nin": {
245
+ // See "in" above for why this splits `matches[2]` instead of `value`.
246
+ const args = matches[2].split(",");
247
+ return Not(In(args));
248
+ }
194
249
  case "range": {
195
- const args = value.split(",");
250
+ // See "in" above for why this splits `matches[2]` instead of `value`.
251
+ const args = matches[2].split(",");
196
252
  if (args.length !== 2) {
197
253
  const msg = StringUtils.findAndReplace(ApiErrorMessages.SEARCH_INVALID_RANGE, {
198
254
  value,
@@ -228,6 +284,45 @@ export class ModelUtils {
228
284
  return param;
229
285
  }
230
286
  }
287
+ /**
288
+ * Recursively verifies that no key in the given value (at any depth, including keys of objects nested inside
289
+ * arrays) is a MongoDB operator (starts with `$`) or uses dot-notation field addressing (contains `.`). Client
290
+ * input is only ever meant to supply plain field values/comparison operands — never raw Mongo query operators —
291
+ * so any such key indicates an attempt to inject arbitrary query behavior (e.g. `$where`, `$expr`, or reaching
292
+ * into a field the API doesn't expose via dot-notation).
293
+ *
294
+ * @param value The value to check, typically a parsed query parameter.
295
+ * @throws {ApiError} If an operator-like or dotted key is found anywhere in `value`.
296
+ */
297
+ static assertNoOperatorInjection(value) {
298
+ if (Array.isArray(value)) {
299
+ for (const item of value) {
300
+ ModelUtils.assertNoOperatorInjection(item);
301
+ }
302
+ }
303
+ else if (value && typeof value === "object") {
304
+ for (const key of Object.keys(value)) {
305
+ if (key.startsWith("$") || key.includes(".")) {
306
+ throw new ApiError(ApiErrors.INVALID_REQUEST, 400, ApiErrorMessages.INVALID_REQUEST);
307
+ }
308
+ ModelUtils.assertNoOperatorInjection(value[key]);
309
+ }
310
+ }
311
+ }
312
+ /**
313
+ * Best-effort check for regex patterns vulnerable to catastrophic backtracking (ReDoS). Rejects patterns that
314
+ * are unreasonably long, or that contain a quantified group whose contents are themselves quantified (e.g.
315
+ * `(a+)+`, `(a*)*`) — the classic shape that causes exponential backtracking in JS's regex engine. This is not
316
+ * an exhaustive defense; it catches the common cases a client would realistically send.
317
+ *
318
+ * @param pattern The user-supplied `like()` pattern.
319
+ */
320
+ static isUnsafeRegexPattern(pattern) {
321
+ if (pattern.length > ModelUtils.MAX_LIKE_PATTERN_LENGTH) {
322
+ return true;
323
+ }
324
+ return /\([^()]*[+*]\)[+*{]/.test(pattern);
325
+ }
231
326
  /**
232
327
  * Given a string containing a parameter value and/or a comparison operation return a MongoDB compatible find value.
233
328
  * e.g.
@@ -256,6 +351,11 @@ export class ModelUtils {
256
351
  value = matches[2];
257
352
  }
258
353
  }
354
+ // `value` is the client-supplied comparison operand — reject any Mongo operator/dotted key hidden
355
+ // inside it, regardless of which (trusted, framework-constructed) operator wrapper it ends up
356
+ // under below. Must run *after* the parse fallback above, not inside its try/catch, so a
357
+ // rejection here isn't silently swallowed as a "not valid JSON" case.
358
+ ModelUtils.assertNoOperatorInjection(value);
259
359
  switch (opName) {
260
360
  case "eq":
261
361
  return value;
@@ -264,15 +364,23 @@ export class ModelUtils {
264
364
  case "gte":
265
365
  return { $gte: value };
266
366
  case "in": {
267
- const args = value.split(",");
367
+ // Split the raw match text, not `value`: a comma-joined list like "1,5" can itself parse
368
+ // as a valid `Date` above (e.g. "1,5" -> Jan 5), leaving `value` a Date with no `.split()`.
369
+ const args = matches[2].split(",");
268
370
  return { $in: args };
269
371
  }
270
372
  case "nin": {
271
- const args = value.split(",");
373
+ // See "in" above for why this splits `matches[2]` instead of `value`.
374
+ const args = matches[2].split(",");
272
375
  return { $nin: args };
273
376
  }
274
- case "like":
275
- return { $regex: value, $options: "i" };
377
+ case "like": {
378
+ const pattern = String(value);
379
+ if (ModelUtils.isUnsafeRegexPattern(pattern)) {
380
+ throw new ApiError(ApiErrors.INVALID_REQUEST, 400, ApiErrorMessages.INVALID_REQUEST);
381
+ }
382
+ return { $regex: pattern, $options: "i" };
383
+ }
276
384
  case "lt":
277
385
  return { $lt: value };
278
386
  case "lte":
@@ -282,7 +390,8 @@ export class ModelUtils {
282
390
  case "not":
283
391
  return { $not: value };
284
392
  case "range": {
285
- const args = value.split(",");
393
+ // See "in" above for why this splits `matches[2]` instead of `value`.
394
+ const args = matches[2].split(",");
286
395
  if (args.length !== 2) {
287
396
  const msg = StringUtils.findAndReplace(ApiErrorMessages.SEARCH_INVALID_RANGE, {
288
397
  value,
@@ -290,31 +399,45 @@ export class ModelUtils {
290
399
  });
291
400
  throw new ApiError(ApiErrors.SEARCH_INVALID_RANGE, 400, msg);
292
401
  }
402
+ // Attempt to parse the range values to native types, falling back to the raw strings
403
+ let gte = args[0];
404
+ let lte = args[1];
293
405
  try {
294
- // Attempt to parse the range values to native types
295
- return { $gte: JSON.parse(args[0]), $lte: JSON.parse(args[1]) };
406
+ gte = JSON.parse(args[0]);
407
+ lte = JSON.parse(args[1]);
296
408
  }
297
409
  catch (err) {
298
- return { $gte: args[0], $lte: args[1] };
410
+ // Not valid JSON — fall back to the raw strings assigned above.
299
411
  }
412
+ ModelUtils.assertNoOperatorInjection(gte);
413
+ ModelUtils.assertNoOperatorInjection(lte);
414
+ return { $gte: gte, $lte: lte };
300
415
  }
301
416
  default:
302
417
  return value;
303
418
  }
304
419
  }
305
420
  else {
421
+ // Attempt to parse the value to a native type, falling back to a date/string if it's not valid JSON
422
+ let parsed;
306
423
  try {
307
- // Attempt to parse the value to a native type
308
- return JSON.parse(param);
424
+ parsed = JSON.parse(param);
309
425
  }
310
426
  catch (err) {
311
- // If an error occurred it's because the value is a string or date, not another type.
312
427
  const date = new Date(param);
313
428
  return !isNaN(date.valueOf()) ? date : param;
314
429
  }
430
+ ModelUtils.assertNoOperatorInjection(parsed);
431
+ return parsed;
315
432
  }
316
433
  }
317
434
  else {
435
+ // A non-string value only reaches here when the caller already parsed the raw query into native
436
+ // types itself (e.g. the `q` base64-encoded JSON query parameter in RouteUtils.wrapMiddleware) —
437
+ // it never passed through the string-only checks above, so it must be validated here instead.
438
+ // Without this, a client could smuggle a raw Mongo operator (e.g. `{"$ne": null}`) straight into
439
+ // the query by supplying it as a JSON object rather than an `op(value)`-encoded string.
440
+ ModelUtils.assertNoOperatorInjection(param);
318
441
  return param;
319
442
  }
320
443
  }
@@ -338,25 +461,24 @@ export class ModelUtils {
338
461
  *
339
462
  * @param modelClass The class definition of the data model to build a search query for.
340
463
  * @param repo The repository to build a search query for.
341
- * @param {any} params The URI parameters for the endpoint that was requested.
342
- * @param {any} queryParams The URI query parameters that were included in the request.
464
+ * @param {any} query The search query parameters to include.
343
465
  * @param {bool} exactMatch Set to true to create a query where parameters are to be matched exactly, otherwise set to false to use a 'contains' search.
344
466
  * @param {any} user The user that is performing the request.
345
467
  * @returns {object} The TypeORM compatible query object.
346
468
  */
347
- static buildSearchQuery(modelClass, repo, params, queryParams, exactMatch = false, user) {
469
+ static buildSearchQuery(modelClass, repo, query = {}, exactMatch = false, user) {
348
470
  // By default we don't want to return deleted recoverable objects unless explicitly requested
349
471
  if (new modelClass() instanceof RecoverableBaseEntity) {
350
- queryParams = {
351
- ...queryParams,
352
- deleted: queryParams && "deleted" in queryParams ? queryParams.deleted : false,
472
+ query = {
473
+ ...query,
474
+ deleted: query && "deleted" in query ? query.deleted : false,
353
475
  };
354
476
  }
355
477
  if (repo instanceof MongoRepository) {
356
- return ModelUtils.buildSearchQueryMongo(modelClass, params, queryParams, exactMatch, user);
478
+ return ModelUtils.buildSearchQueryMongo(modelClass, query, exactMatch, user);
357
479
  }
358
480
  else {
359
- return ModelUtils.buildSearchQuerySQL(modelClass, params, queryParams, exactMatch, user);
481
+ return ModelUtils.buildSearchQuerySQL(modelClass, query, exactMatch, user);
360
482
  }
361
483
  }
362
484
  /**
@@ -376,26 +498,22 @@ export class ModelUtils {
376
498
  * When no operator is provided the comparison will always be evaluated as `eq`.
377
499
  *
378
500
  * @param modelClass The class definition of the data model to build a search query for.
379
- * @param {any} params The URI parameters for the endpoint that was requested.
380
- * @param {any} queryParams The URI query parameters that were included in the request.
501
+ * @param {any} query The search query parameters to include.
381
502
  * @param {bool} exactMatch Set to true to create a query where parameters are to be matched exactly, otherwise set to false to use a 'contains' search.
382
503
  * @param {any} user The user that is performing the request.
383
504
  * @returns {object} The TypeORM compatible query object.
384
505
  */
385
- static buildSearchQuerySQL(modelClass, params, queryParams, exactMatch = false, user) {
386
- const query = {};
387
- query.where = [];
388
- // Add the URL parameters
389
- for (const key in params) {
506
+ static buildSearchQuerySQL(modelClass, query = {}, exactMatch = false, user) {
507
+ const result = {};
508
+ result.where = [];
509
+ // Pre-process any query values (e.g. the `me` identifier)
510
+ for (const key in query) {
390
511
  // If the value is 'me' that's a special keyword to reference the user ID.
391
- if (params[key] === "me") {
512
+ if (query[key] === "me") {
392
513
  if (!user) {
393
514
  throw new ApiError(ApiErrors.SEARCH_INVALID_ME_REFERENCE, 403, ApiErrorMessages.SEARCH_INVALID_ME_REFERENCE);
394
515
  }
395
- query.where[key] = user.uid;
396
- }
397
- else {
398
- query.where[key] = params[key];
516
+ query[key] = user.uid;
399
517
  }
400
518
  }
401
519
  // Query parameters can be a single value or multiple. In the case of multiple we want to perform an OR
@@ -403,8 +521,8 @@ export class ModelUtils {
403
521
  // the parameters as well.
404
522
  // So first let's find out how many queries in total we are going to need.
405
523
  let numQueries = 1;
406
- for (const key in queryParams) {
407
- const value = queryParams[key];
524
+ for (const key in query) {
525
+ const value = query[key];
408
526
  if (Array.isArray(value)) {
409
527
  if (value.length > numQueries) {
410
528
  numQueries = value.length;
@@ -414,20 +532,20 @@ export class ModelUtils {
414
532
  // logger?.debug(`Query params: ${JSON.stringify(queryParams)}`);
415
533
  // Now go through each query paramater. If the parameter is a single value, add it to each query object. If it's an array,
416
534
  // add only one value to each query object.
417
- for (let key in queryParams) {
535
+ for (let key in query) {
418
536
  // Ignore reserved query parameters
419
537
  if (key.match(REGEX_RESERVED_QUERY_PARAMS)) {
420
538
  continue;
421
539
  }
422
540
  // Limit, page and sort are reserved for specifying query limits
423
541
  if (key.match(REGEX_QUERY_LIMITS)) {
424
- let value = queryParams[key];
542
+ let value = query[key];
425
543
  if (key === "limit") {
426
544
  key = "take";
427
- query[key] = Number(value);
545
+ result[key] = Number(value);
428
546
  }
429
547
  else if (key === "page") {
430
- query[key] = Number(value);
548
+ result[key] = Number(value);
431
549
  }
432
550
  else if (key === "sort") {
433
551
  key = "order";
@@ -442,42 +560,45 @@ export class ModelUtils {
442
560
  value = newValue;
443
561
  }
444
562
  }
445
- query[key] = value;
563
+ result[key] = value;
446
564
  }
447
565
  continue;
448
566
  }
449
- if (Array.isArray(queryParams[key])) {
450
- // Add each value in the array to each corresponding query
451
- let i = 0;
452
- for (const value of queryParams[key]) {
453
- if (!query.where[i]) {
454
- query.where[i] = {};
567
+ if (Array.isArray(query[key])) {
568
+ // Add each value in the array to each corresponding query. Multi-valued keys are "zipped"
569
+ // together via `numQueries` above; if this key's array is shorter than another key's, pad the
570
+ // remaining branches by repeating this key's own last value rather than leaving the key unset —
571
+ // an unset key would match ANY value, silently dropping this filter from those branches.
572
+ const values = query[key];
573
+ for (let i = 0; i < numQueries; i++) {
574
+ if (!result.where[i]) {
575
+ result.where[i] = {};
455
576
  }
456
- query.where[i][key] = ModelUtils.getQueryParamValue(value);
457
- i++;
577
+ const value = i < values.length ? values[i] : values[values.length - 1];
578
+ result.where[i][key] = ModelUtils.getQueryParamValue(value);
458
579
  }
459
580
  }
460
581
  else {
461
582
  // Add the parameter to every query
462
583
  for (let i = 0; i < numQueries; i++) {
463
- if (!query.where[i]) {
464
- query.where[i] = {};
584
+ if (!result.where[i]) {
585
+ result.where[i] = {};
465
586
  }
466
- query.where[i][key] = ModelUtils.getQueryParamValue(queryParams[key]);
587
+ result.where[i][key] = ModelUtils.getQueryParamValue(query[key]);
467
588
  }
468
589
  }
469
590
  }
470
- if (query.where.length === 0) {
471
- delete query.where;
591
+ if (result.where.length === 0) {
592
+ delete result.where;
472
593
  }
473
- if (query.take) {
474
- query.take = Math.min(query.take, 1000);
594
+ if (result.take) {
595
+ result.take = Math.min(result.take, 1000);
475
596
  }
476
597
  else {
477
- query.take = 100;
598
+ result.take = 100;
478
599
  }
479
- query.page = query.page ? query.page : 0;
480
- return query;
600
+ result.page = result.page ? result.page : 0;
601
+ return result;
481
602
  }
482
603
  /**
483
604
  * Builds a MongoDB compatible query object for the given criteria. Query params can have a value containing a
@@ -498,37 +619,47 @@ export class ModelUtils {
498
619
  * NOTE: The result of this function is only compatible with the `aggregate()` function.
499
620
  *
500
621
  * @param modelClass The class definition of the data model to build a search query for.
501
- * @param {any} params The URI parameters for the endpoint that was requested.
502
- * @param {any} queryParams The URI query parameters that were included in the request.
622
+ * @param {any} query The search query parameters to include.
503
623
  * @param {bool} exactMatch Set to true to create a query where parameters are to be matched exactly, otherwise set to false to use a 'contains' search.
504
624
  * @param {any} user The user that is performing the request.
505
- * @returns {object} The TypeORM compatible query object.
625
+ * @returns {object} The MongoDB compatible query object.
506
626
  */
507
- static buildSearchQueryMongo(modelClass, params, queryParams, exactMatch = false, user) {
627
+ static buildSearchQueryMongo(modelClass, query = {}, exactMatch = false, user) {
508
628
  const queries = [{}];
509
629
  let sort = undefined;
510
- // Add the URL parameters
511
- for (const key in params) {
512
- // If the value is 'me' that's a special keyword to reference the user ID.
513
- if (params[key] === "me") {
514
- if (!user) {
515
- throw new ApiError(ApiErrors.SEARCH_INVALID_ME_REFERENCE, 403, ApiErrorMessages.SEARCH_INVALID_ME_REFERENCE);
516
- }
517
- queries[0][key] = user.uid;
630
+ // logger?.debug(`Query params: ${JSON.stringify(queryParams)}`);
631
+ // Query parameters can be a single value or multiple. In the case of multiple we want to perform an OR
632
+ // operation for each value, "zipped" together with any other multi-valued parameters (see the equivalent
633
+ // two-pass logic in buildSearchQuerySQL) — so first determine how many OR branches we need in total and
634
+ // pre-allocate them, before any key gets applied to a subset of branches.
635
+ let numQueries = 1;
636
+ for (const key in query) {
637
+ if (key === "$or" || key.match(REGEX_RESERVED_QUERY_PARAMS) || key.match(REGEX_QUERY_LIMITS)) {
638
+ continue;
518
639
  }
519
- else {
520
- queries[0][key] = params[key];
640
+ const value = query[key];
641
+ if (Array.isArray(value) && value.length > numQueries) {
642
+ numQueries = value.length;
521
643
  }
522
644
  }
523
- // logger?.debug(`Query params: ${JSON.stringify(queryParams)}`);
524
- for (const key in queryParams) {
645
+ for (let i = 1; i < numQueries; i++) {
646
+ queries[i] = {};
647
+ }
648
+ for (const key in query) {
525
649
  // Ignore reserved query parameters
526
650
  if (key.match(REGEX_RESERVED_QUERY_PARAMS)) {
527
651
  continue;
528
652
  }
653
+ // If the value is 'me' that's a special keyword to reference the user ID.
654
+ if (query[key] === "me") {
655
+ if (!user) {
656
+ throw new ApiError(ApiErrors.SEARCH_INVALID_ME_REFERENCE, 403, ApiErrorMessages.SEARCH_INVALID_ME_REFERENCE);
657
+ }
658
+ query[key] = user.uid;
659
+ }
529
660
  // Limit, page and sort are reserved for specifying query limits
530
661
  if (key.match(REGEX_QUERY_LIMITS)) {
531
- let value = queryParams[key];
662
+ let value = query[key];
532
663
  if (key === "sort") {
533
664
  if (typeof value === "string") {
534
665
  if (value.match(REGEX_QUERY_SORT_STRING)) {
@@ -554,6 +685,9 @@ export class ModelUtils {
554
685
  if (typeof value === "number") {
555
686
  sort[key] = value;
556
687
  }
688
+ else if (typeof value !== "string") {
689
+ return;
690
+ }
557
691
  else if (value.toUpperCase() === "ASC") {
558
692
  sort[key] = 1;
559
693
  }
@@ -564,35 +698,45 @@ export class ModelUtils {
564
698
  }
565
699
  continue;
566
700
  }
701
+ // Reject any other Mongo operator key or dot-notation field path outright — client input may only
702
+ // supply plain field names, never raw query operators (`$or` is the one deliberate exception, handled
703
+ // just below; its sub-queries are validated recursively when they're built).
704
+ if (key !== "$or" && (key.startsWith("$") || key.includes("."))) {
705
+ throw new ApiError(ApiErrors.INVALID_REQUEST, 400, ApiErrorMessages.INVALID_REQUEST);
706
+ }
567
707
  if (key === "$or") {
568
708
  // Array of OR queries
569
709
  let orResults = [];
570
- for (const query of queryParams[key]) {
571
- const subQueryOrResult = this.buildSearchQueryMongo(modelClass, undefined, query, exactMatch, user);
710
+ for (const q of query[key]) {
711
+ const subQueryOrResult = this.buildSearchQueryMongo(modelClass, q, exactMatch, user);
572
712
  const validSubQueryResult = Array.isArray(subQueryOrResult) && subQueryOrResult.length > 0
573
713
  ? subQueryOrResult[0]["$match"]
574
714
  : subQueryOrResult["$match"];
575
715
  validSubQueryResult && orResults.push(validSubQueryResult);
576
716
  }
577
- queries[0] = { $or: orResults };
717
+ // Merge into whatever conditions earlier keys (including the injected soft-delete filter)
718
+ // already placed on each branch — replacing outright would silently discard them, and merging
719
+ // only into queries[0] would silently drop the $or constraint from any other zipped branch.
720
+ for (let i = 0; i < numQueries; i++) {
721
+ queries[i] = { ...queries[i], $or: orResults };
722
+ }
578
723
  continue;
579
724
  }
580
- if (Array.isArray(queryParams[key])) {
581
- // Add each value in the array to each corresponding query
582
- const conditions = [];
583
- for (let i = 0; i < queryParams[key].length; i++) {
584
- const value = ModelUtils.getQueryParamValueMongo(queryParams[key][i]);
585
- if (!queries[i]) {
586
- queries[i] = {
587
- ...queries[0],
588
- };
589
- }
590
- queries[i][key] = value;
725
+ if (Array.isArray(query[key])) {
726
+ // Add each value in the array to each corresponding query, zipped per `numQueries` above. If
727
+ // this key's array is shorter than another key's, pad the remaining branches by repeating this
728
+ // key's own last value rather than leaving the key unset — an unset key would match ANY value,
729
+ // silently dropping this filter from those branches. Injection safety is already enforced
730
+ // inside getQueryParamValueMongo() itself, at the point the client-supplied value is parsed.
731
+ const values = query[key];
732
+ for (let i = 0; i < numQueries; i++) {
733
+ const raw = i < values.length ? values[i] : values[values.length - 1];
734
+ queries[i][key] = ModelUtils.getQueryParamValueMongo(raw);
591
735
  }
592
736
  }
593
737
  else {
594
- const value = ModelUtils.getQueryParamValueMongo(queryParams[key]);
595
- for (let i = 0; i < queries.length; i++) {
738
+ const value = ModelUtils.getQueryParamValueMongo(query[key]);
739
+ for (let i = 0; i < numQueries; i++) {
596
740
  queries[i][key] = value;
597
741
  }
598
742
  }
@@ -635,7 +779,7 @@ export class ModelUtils {
635
779
  await classLoader.load();
636
780
  // Go through each class and determine which ones implements the `@Model` decorator.
637
781
  classLoader.getClasses().forEach((clazz, name) => {
638
- const isModel = Reflect.getMetadata("rrst:datastore", clazz) !== undefined;
782
+ const isModel = Reflect.getMetadata("rrst:datasource", clazz) !== undefined;
639
783
  if (isModel) {
640
784
  result.set(name, clazz);
641
785
  }
@@ -649,4 +793,7 @@ export class ModelUtils {
649
793
  }
650
794
  }
651
795
  ModelUtils.idPropertyCache = new Map();
796
+ ModelUtils.readOnlyPropertyCache = new Map();
797
+ /** Maximum accepted length of a client-supplied `like()` search pattern. */
798
+ ModelUtils.MAX_LIKE_PATTERN_LENGTH = 100;
652
799
  //# sourceMappingURL=ModelUtils.js.map