@rebasepro/server-mongodb 0.0.1-canary.09e5ec5

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 (286) hide show
  1. package/LICENSE +6 -0
  2. package/dist/ensure-collections-CNrcwVgY.js +74 -0
  3. package/dist/ensure-collections-CNrcwVgY.js.map +1 -0
  4. package/dist/ensure-history-collection-DBIiwmCm.js +15 -0
  5. package/dist/ensure-history-collection-DBIiwmCm.js.map +1 -0
  6. package/dist/index.es.js +1734 -0
  7. package/dist/index.es.js.map +1 -0
  8. package/dist/index.umd.js +2043 -0
  9. package/dist/index.umd.js.map +1 -0
  10. package/dist/server-core/src/api/ast-schema-editor.d.ts +22 -0
  11. package/dist/server-core/src/api/ast-schema-editor.d.ts.map +1 -0
  12. package/dist/server-core/src/api/errors.d.ts +36 -0
  13. package/dist/server-core/src/api/errors.d.ts.map +1 -0
  14. package/dist/server-core/src/api/graphql/graphql-schema-generator.d.ts +36 -0
  15. package/dist/server-core/src/api/graphql/graphql-schema-generator.d.ts.map +1 -0
  16. package/dist/server-core/src/api/graphql/index.d.ts +2 -0
  17. package/dist/server-core/src/api/graphql/index.d.ts.map +1 -0
  18. package/dist/server-core/src/api/index.d.ts +10 -0
  19. package/dist/server-core/src/api/index.d.ts.map +1 -0
  20. package/dist/server-core/src/api/openapi-generator.d.ts +17 -0
  21. package/dist/server-core/src/api/openapi-generator.d.ts.map +1 -0
  22. package/dist/server-core/src/api/rest/api-generator.d.ts +65 -0
  23. package/dist/server-core/src/api/rest/api-generator.d.ts.map +1 -0
  24. package/dist/server-core/src/api/rest/index.d.ts +2 -0
  25. package/dist/server-core/src/api/rest/index.d.ts.map +1 -0
  26. package/dist/server-core/src/api/rest/query-parser.d.ts +10 -0
  27. package/dist/server-core/src/api/rest/query-parser.d.ts.map +1 -0
  28. package/dist/server-core/src/api/schema-editor-routes.d.ts +4 -0
  29. package/dist/server-core/src/api/schema-editor-routes.d.ts.map +1 -0
  30. package/dist/server-core/src/api/server.d.ts +41 -0
  31. package/dist/server-core/src/api/server.d.ts.map +1 -0
  32. package/dist/server-core/src/api/types.d.ts +91 -0
  33. package/dist/server-core/src/api/types.d.ts.map +1 -0
  34. package/dist/server-core/src/auth/admin-routes.d.ts +17 -0
  35. package/dist/server-core/src/auth/admin-routes.d.ts.map +1 -0
  36. package/dist/server-core/src/auth/apple-oauth.d.ts +31 -0
  37. package/dist/server-core/src/auth/apple-oauth.d.ts.map +1 -0
  38. package/dist/server-core/src/auth/bitbucket-oauth.d.ts +12 -0
  39. package/dist/server-core/src/auth/bitbucket-oauth.d.ts.map +1 -0
  40. package/dist/server-core/src/auth/discord-oauth.d.ts +15 -0
  41. package/dist/server-core/src/auth/discord-oauth.d.ts.map +1 -0
  42. package/dist/server-core/src/auth/facebook-oauth.d.ts +15 -0
  43. package/dist/server-core/src/auth/facebook-oauth.d.ts.map +1 -0
  44. package/dist/server-core/src/auth/github-oauth.d.ts +16 -0
  45. package/dist/server-core/src/auth/github-oauth.d.ts.map +1 -0
  46. package/dist/server-core/src/auth/gitlab-oauth.d.ts +14 -0
  47. package/dist/server-core/src/auth/gitlab-oauth.d.ts.map +1 -0
  48. package/dist/server-core/src/auth/google-oauth.d.ts +15 -0
  49. package/dist/server-core/src/auth/google-oauth.d.ts.map +1 -0
  50. package/dist/server-core/src/auth/index.d.ts +24 -0
  51. package/dist/server-core/src/auth/index.d.ts.map +1 -0
  52. package/dist/server-core/src/auth/interfaces.d.ts +310 -0
  53. package/dist/server-core/src/auth/interfaces.d.ts.map +1 -0
  54. package/dist/server-core/src/auth/jwt.d.ts +44 -0
  55. package/dist/server-core/src/auth/jwt.d.ts.map +1 -0
  56. package/dist/server-core/src/auth/linkedin-oauth.d.ts +19 -0
  57. package/dist/server-core/src/auth/linkedin-oauth.d.ts.map +1 -0
  58. package/dist/server-core/src/auth/microsoft-oauth.d.ts +17 -0
  59. package/dist/server-core/src/auth/microsoft-oauth.d.ts.map +1 -0
  60. package/dist/server-core/src/auth/middleware.d.ts +82 -0
  61. package/dist/server-core/src/auth/middleware.d.ts.map +1 -0
  62. package/dist/server-core/src/auth/password.d.ts +23 -0
  63. package/dist/server-core/src/auth/password.d.ts.map +1 -0
  64. package/dist/server-core/src/auth/rate-limiter.d.ts +32 -0
  65. package/dist/server-core/src/auth/rate-limiter.d.ts.map +1 -0
  66. package/dist/server-core/src/auth/routes.d.ts +28 -0
  67. package/dist/server-core/src/auth/routes.d.ts.map +1 -0
  68. package/dist/server-core/src/auth/slack-oauth.d.ts +13 -0
  69. package/dist/server-core/src/auth/slack-oauth.d.ts.map +1 -0
  70. package/dist/server-core/src/auth/spotify-oauth.d.ts +13 -0
  71. package/dist/server-core/src/auth/spotify-oauth.d.ts.map +1 -0
  72. package/dist/server-core/src/auth/twitter-oauth.d.ts +19 -0
  73. package/dist/server-core/src/auth/twitter-oauth.d.ts.map +1 -0
  74. package/dist/server-core/src/collections/BackendCollectionRegistry.d.ts +14 -0
  75. package/dist/server-core/src/collections/BackendCollectionRegistry.d.ts.map +1 -0
  76. package/dist/server-core/src/collections/loader.d.ts +6 -0
  77. package/dist/server-core/src/collections/loader.d.ts.map +1 -0
  78. package/dist/server-core/src/cron/cron-loader.d.ts +18 -0
  79. package/dist/server-core/src/cron/cron-loader.d.ts.map +1 -0
  80. package/dist/server-core/src/cron/cron-routes.d.ts +15 -0
  81. package/dist/server-core/src/cron/cron-routes.d.ts.map +1 -0
  82. package/dist/server-core/src/cron/cron-scheduler.d.ts +62 -0
  83. package/dist/server-core/src/cron/cron-scheduler.d.ts.map +1 -0
  84. package/dist/server-core/src/cron/cron-store.d.ts +33 -0
  85. package/dist/server-core/src/cron/cron-store.d.ts.map +1 -0
  86. package/dist/server-core/src/cron/index.d.ts +7 -0
  87. package/dist/server-core/src/cron/index.d.ts.map +1 -0
  88. package/dist/server-core/src/db/interfaces.d.ts +19 -0
  89. package/dist/server-core/src/db/interfaces.d.ts.map +1 -0
  90. package/dist/server-core/src/email/index.d.ts +7 -0
  91. package/dist/server-core/src/email/index.d.ts.map +1 -0
  92. package/dist/server-core/src/email/smtp-email-service.d.ts +26 -0
  93. package/dist/server-core/src/email/smtp-email-service.d.ts.map +1 -0
  94. package/dist/server-core/src/email/templates.d.ts +43 -0
  95. package/dist/server-core/src/email/templates.d.ts.map +1 -0
  96. package/dist/server-core/src/email/types.d.ts +108 -0
  97. package/dist/server-core/src/email/types.d.ts.map +1 -0
  98. package/dist/server-core/src/functions/function-loader.d.ts +18 -0
  99. package/dist/server-core/src/functions/function-loader.d.ts.map +1 -0
  100. package/dist/server-core/src/functions/function-routes.d.ts +11 -0
  101. package/dist/server-core/src/functions/function-routes.d.ts.map +1 -0
  102. package/dist/server-core/src/functions/index.d.ts +4 -0
  103. package/dist/server-core/src/functions/index.d.ts.map +1 -0
  104. package/dist/server-core/src/history/history-routes.d.ts +24 -0
  105. package/dist/server-core/src/history/history-routes.d.ts.map +1 -0
  106. package/dist/server-core/src/history/index.d.ts +2 -0
  107. package/dist/server-core/src/history/index.d.ts.map +1 -0
  108. package/dist/server-core/src/index.d.ts +30 -0
  109. package/dist/server-core/src/index.d.ts.map +1 -0
  110. package/dist/server-core/src/init.d.ts +160 -0
  111. package/dist/server-core/src/init.d.ts.map +1 -0
  112. package/dist/server-core/src/serve-spa.d.ts +31 -0
  113. package/dist/server-core/src/serve-spa.d.ts.map +1 -0
  114. package/dist/server-core/src/services/driver-registry.d.ts +79 -0
  115. package/dist/server-core/src/services/driver-registry.d.ts.map +1 -0
  116. package/dist/server-core/src/singleton.d.ts +36 -0
  117. package/dist/server-core/src/singleton.d.ts.map +1 -0
  118. package/dist/server-core/src/storage/LocalStorageController.d.ts +47 -0
  119. package/dist/server-core/src/storage/LocalStorageController.d.ts.map +1 -0
  120. package/dist/server-core/src/storage/S3StorageController.d.ts +37 -0
  121. package/dist/server-core/src/storage/S3StorageController.d.ts.map +1 -0
  122. package/dist/server-core/src/storage/index.d.ts +26 -0
  123. package/dist/server-core/src/storage/index.d.ts.map +1 -0
  124. package/dist/server-core/src/storage/routes.d.ts +39 -0
  125. package/dist/server-core/src/storage/routes.d.ts.map +1 -0
  126. package/dist/server-core/src/storage/storage-registry.d.ts +79 -0
  127. package/dist/server-core/src/storage/storage-registry.d.ts.map +1 -0
  128. package/dist/server-core/src/storage/types.d.ts +104 -0
  129. package/dist/server-core/src/storage/types.d.ts.map +1 -0
  130. package/dist/server-core/src/types/index.d.ts +12 -0
  131. package/dist/server-core/src/types/index.d.ts.map +1 -0
  132. package/dist/server-core/src/utils/dev-port.d.ts +36 -0
  133. package/dist/server-core/src/utils/dev-port.d.ts.map +1 -0
  134. package/dist/server-core/src/utils/logger.d.ts +32 -0
  135. package/dist/server-core/src/utils/logger.d.ts.map +1 -0
  136. package/dist/server-core/src/utils/logging.d.ts +10 -0
  137. package/dist/server-core/src/utils/logging.d.ts.map +1 -0
  138. package/dist/server-core/src/utils/request-logger.d.ts +20 -0
  139. package/dist/server-core/src/utils/request-logger.d.ts.map +1 -0
  140. package/dist/server-core/src/utils/sql.d.ts +28 -0
  141. package/dist/server-core/src/utils/sql.d.ts.map +1 -0
  142. package/dist/server-mongodb/src/MongoBootstrapper.d.ts +18 -0
  143. package/dist/server-mongodb/src/MongoBootstrapper.d.ts.map +1 -0
  144. package/dist/server-mongodb/src/auth/ensure-collections.d.ts +3 -0
  145. package/dist/server-mongodb/src/auth/ensure-collections.d.ts.map +1 -0
  146. package/dist/server-mongodb/src/auth/services.d.ts +135 -0
  147. package/dist/server-mongodb/src/auth/services.d.ts.map +1 -0
  148. package/dist/server-mongodb/src/connection.d.ts +35 -0
  149. package/dist/server-mongodb/src/connection.d.ts.map +1 -0
  150. package/dist/server-mongodb/src/db/MongoConditionBuilder.d.ts +64 -0
  151. package/dist/server-mongodb/src/db/MongoConditionBuilder.d.ts.map +1 -0
  152. package/dist/server-mongodb/src/db/MongoEntityService.d.ts +98 -0
  153. package/dist/server-mongodb/src/db/MongoEntityService.d.ts.map +1 -0
  154. package/dist/server-mongodb/src/factory.d.ts +142 -0
  155. package/dist/server-mongodb/src/factory.d.ts.map +1 -0
  156. package/dist/server-mongodb/src/history/ensure-history-collection.d.ts +3 -0
  157. package/dist/server-mongodb/src/history/ensure-history-collection.d.ts.map +1 -0
  158. package/dist/server-mongodb/src/index.d.ts +18 -0
  159. package/dist/server-mongodb/src/index.d.ts.map +1 -0
  160. package/dist/server-mongodb/src/services/MongoDriver.d.ts +83 -0
  161. package/dist/server-mongodb/src/services/MongoDriver.d.ts.map +1 -0
  162. package/dist/server-mongodb/src/services/MongoHistoryService.d.ts +37 -0
  163. package/dist/server-mongodb/src/services/MongoHistoryService.d.ts.map +1 -0
  164. package/dist/server-mongodb/src/services/MongoRealtimeService.d.ts +86 -0
  165. package/dist/server-mongodb/src/services/MongoRealtimeService.d.ts.map +1 -0
  166. package/dist/server-mongodb/src/useMongoDriver.d.ts +18 -0
  167. package/dist/server-mongodb/src/useMongoDriver.d.ts.map +1 -0
  168. package/dist/server-mongodb/src/utils.d.ts +10 -0
  169. package/dist/server-mongodb/src/utils.d.ts.map +1 -0
  170. package/dist/server-mongodb/src/websocket.d.ts +7 -0
  171. package/dist/server-mongodb/src/websocket.d.ts.map +1 -0
  172. package/dist/types/src/controllers/analytics_controller.d.ts +8 -0
  173. package/dist/types/src/controllers/analytics_controller.d.ts.map +1 -0
  174. package/dist/types/src/controllers/auth.d.ts +120 -0
  175. package/dist/types/src/controllers/auth.d.ts.map +1 -0
  176. package/dist/types/src/controllers/client.d.ts +171 -0
  177. package/dist/types/src/controllers/client.d.ts.map +1 -0
  178. package/dist/types/src/controllers/collection_registry.d.ts +46 -0
  179. package/dist/types/src/controllers/collection_registry.d.ts.map +1 -0
  180. package/dist/types/src/controllers/customization_controller.d.ts +61 -0
  181. package/dist/types/src/controllers/customization_controller.d.ts.map +1 -0
  182. package/dist/types/src/controllers/data.d.ts +169 -0
  183. package/dist/types/src/controllers/data.d.ts.map +1 -0
  184. package/dist/types/src/controllers/data_driver.d.ts +161 -0
  185. package/dist/types/src/controllers/data_driver.d.ts.map +1 -0
  186. package/dist/types/src/controllers/database_admin.d.ts +12 -0
  187. package/dist/types/src/controllers/database_admin.d.ts.map +1 -0
  188. package/dist/types/src/controllers/dialogs_controller.d.ts +37 -0
  189. package/dist/types/src/controllers/dialogs_controller.d.ts.map +1 -0
  190. package/dist/types/src/controllers/effective_role.d.ts +5 -0
  191. package/dist/types/src/controllers/effective_role.d.ts.map +1 -0
  192. package/dist/types/src/controllers/email.d.ts +35 -0
  193. package/dist/types/src/controllers/email.d.ts.map +1 -0
  194. package/dist/types/src/controllers/index.d.ts +19 -0
  195. package/dist/types/src/controllers/index.d.ts.map +1 -0
  196. package/dist/types/src/controllers/local_config_persistence.d.ts +21 -0
  197. package/dist/types/src/controllers/local_config_persistence.d.ts.map +1 -0
  198. package/dist/types/src/controllers/navigation.d.ts +214 -0
  199. package/dist/types/src/controllers/navigation.d.ts.map +1 -0
  200. package/dist/types/src/controllers/registry.d.ts +55 -0
  201. package/dist/types/src/controllers/registry.d.ts.map +1 -0
  202. package/dist/types/src/controllers/side_dialogs_controller.d.ts +68 -0
  203. package/dist/types/src/controllers/side_dialogs_controller.d.ts.map +1 -0
  204. package/dist/types/src/controllers/side_entity_controller.d.ts +91 -0
  205. package/dist/types/src/controllers/side_entity_controller.d.ts.map +1 -0
  206. package/dist/types/src/controllers/snackbar.d.ts +25 -0
  207. package/dist/types/src/controllers/snackbar.d.ts.map +1 -0
  208. package/dist/types/src/controllers/storage.d.ts +172 -0
  209. package/dist/types/src/controllers/storage.d.ts.map +1 -0
  210. package/dist/types/src/index.d.ts +5 -0
  211. package/dist/types/src/index.d.ts.map +1 -0
  212. package/dist/types/src/rebase_context.d.ts +106 -0
  213. package/dist/types/src/rebase_context.d.ts.map +1 -0
  214. package/dist/types/src/types/backend.d.ts +537 -0
  215. package/dist/types/src/types/backend.d.ts.map +1 -0
  216. package/dist/types/src/types/builders.d.ts +16 -0
  217. package/dist/types/src/types/builders.d.ts.map +1 -0
  218. package/dist/types/src/types/chips.d.ts +6 -0
  219. package/dist/types/src/types/chips.d.ts.map +1 -0
  220. package/dist/types/src/types/collections.d.ts +857 -0
  221. package/dist/types/src/types/collections.d.ts.map +1 -0
  222. package/dist/types/src/types/cron.d.ts +103 -0
  223. package/dist/types/src/types/cron.d.ts.map +1 -0
  224. package/dist/types/src/types/data_source.d.ts +65 -0
  225. package/dist/types/src/types/data_source.d.ts.map +1 -0
  226. package/dist/types/src/types/entities.d.ts +146 -0
  227. package/dist/types/src/types/entities.d.ts.map +1 -0
  228. package/dist/types/src/types/entity_actions.d.ts +99 -0
  229. package/dist/types/src/types/entity_actions.d.ts.map +1 -0
  230. package/dist/types/src/types/entity_callbacks.d.ts +174 -0
  231. package/dist/types/src/types/entity_callbacks.d.ts.map +1 -0
  232. package/dist/types/src/types/entity_link_builder.d.ts +8 -0
  233. package/dist/types/src/types/entity_link_builder.d.ts.map +1 -0
  234. package/dist/types/src/types/entity_overrides.d.ts +11 -0
  235. package/dist/types/src/types/entity_overrides.d.ts.map +1 -0
  236. package/dist/types/src/types/entity_views.d.ts +62 -0
  237. package/dist/types/src/types/entity_views.d.ts.map +1 -0
  238. package/dist/types/src/types/export_import.d.ts +22 -0
  239. package/dist/types/src/types/export_import.d.ts.map +1 -0
  240. package/dist/types/src/types/index.d.ts +24 -0
  241. package/dist/types/src/types/index.d.ts.map +1 -0
  242. package/dist/types/src/types/locales.d.ts +5 -0
  243. package/dist/types/src/types/locales.d.ts.map +1 -0
  244. package/dist/types/src/types/modify_collections.d.ts +6 -0
  245. package/dist/types/src/types/modify_collections.d.ts.map +1 -0
  246. package/dist/types/src/types/plugins.d.ts +280 -0
  247. package/dist/types/src/types/plugins.d.ts.map +1 -0
  248. package/dist/types/src/types/properties.d.ts +1177 -0
  249. package/dist/types/src/types/properties.d.ts.map +1 -0
  250. package/dist/types/src/types/property_config.d.ts +71 -0
  251. package/dist/types/src/types/property_config.d.ts.map +1 -0
  252. package/dist/types/src/types/relations.d.ts +337 -0
  253. package/dist/types/src/types/relations.d.ts.map +1 -0
  254. package/dist/types/src/types/slots.d.ts +253 -0
  255. package/dist/types/src/types/slots.d.ts.map +1 -0
  256. package/dist/types/src/types/translations.d.ts +871 -0
  257. package/dist/types/src/types/translations.d.ts.map +1 -0
  258. package/dist/types/src/types/user_management_delegate.d.ts +122 -0
  259. package/dist/types/src/types/user_management_delegate.d.ts.map +1 -0
  260. package/dist/types/src/types/websockets.d.ts +79 -0
  261. package/dist/types/src/types/websockets.d.ts.map +1 -0
  262. package/dist/types/src/users/index.d.ts +3 -0
  263. package/dist/types/src/users/index.d.ts.map +1 -0
  264. package/dist/types/src/users/roles.d.ts +23 -0
  265. package/dist/types/src/users/roles.d.ts.map +1 -0
  266. package/dist/types/src/users/user.d.ts +47 -0
  267. package/dist/types/src/users/user.d.ts.map +1 -0
  268. package/dist/websocket-BZlPuJrt.js +220 -0
  269. package/dist/websocket-BZlPuJrt.js.map +1 -0
  270. package/package.json +79 -0
  271. package/src/MongoBootstrapper.ts +177 -0
  272. package/src/auth/ensure-collections.ts +94 -0
  273. package/src/auth/services.ts +638 -0
  274. package/src/connection.ts +60 -0
  275. package/src/db/MongoConditionBuilder.ts +181 -0
  276. package/src/db/MongoEntityService.ts +350 -0
  277. package/src/factory.ts +289 -0
  278. package/src/history/ensure-history-collection.ts +19 -0
  279. package/src/index.ts +25 -0
  280. package/src/services/MongoDriver.ts +297 -0
  281. package/src/services/MongoDriver.ts.backup +266 -0
  282. package/src/services/MongoHistoryService.ts +154 -0
  283. package/src/services/MongoRealtimeService.ts +394 -0
  284. package/src/useMongoDriver.ts +519 -0
  285. package/src/utils.ts +28 -0
  286. package/src/websocket.ts +257 -0
@@ -0,0 +1,1734 @@
1
+ import { MongoClient, ObjectId } from "mongodb";
2
+ class MongoDBConnection {
3
+ constructor(db, client) {
4
+ this.db = db;
5
+ this.client = client;
6
+ }
7
+ type = "mongodb";
8
+ get isConnected() {
9
+ try {
10
+ const clientInternal = this.client;
11
+ return clientInternal.topology?.isConnected?.() ?? false;
12
+ } catch {
13
+ return false;
14
+ }
15
+ }
16
+ async close() {
17
+ await this.client.close();
18
+ }
19
+ }
20
+ async function createMongoDBConnection(connectionString, databaseName) {
21
+ const client = new MongoClient(connectionString);
22
+ await client.connect();
23
+ const db = client.db(databaseName);
24
+ return new MongoDBConnection(db, client);
25
+ }
26
+ const REBASE_TO_MONGO_OP = {
27
+ "<": "$lt",
28
+ "<=": "$lte",
29
+ "==": "$eq",
30
+ "!=": "$ne",
31
+ ">=": "$gte",
32
+ ">": "$gt",
33
+ "array-contains": "$elemMatch",
34
+ "array-contains-any": "$in",
35
+ "in": "$in",
36
+ "not-in": "$nin"
37
+ };
38
+ class MongoConditionBuilder {
39
+ /**
40
+ * Build MongoDB filter conditions from Rebase FilterValues
41
+ *
42
+ * @param filter - Rebase filter values
43
+ * @returns Array of MongoDB filter objects
44
+ */
45
+ static buildFilterConditions(filter) {
46
+ if (!filter) return [];
47
+ const conditions = [];
48
+ for (const [field, filterParam] of Object.entries(filter)) {
49
+ if (!filterParam) continue;
50
+ const [op, value] = filterParam;
51
+ const mongoOp = REBASE_TO_MONGO_OP[op];
52
+ if (!mongoOp) {
53
+ console.warn(`Unsupported filter operator: ${op}`);
54
+ continue;
55
+ }
56
+ if (op === "array-contains") {
57
+ conditions.push({
58
+ [field]: { $elemMatch: { $eq: value } }
59
+ });
60
+ } else {
61
+ conditions.push({
62
+ [field]: { [mongoOp]: value }
63
+ });
64
+ }
65
+ }
66
+ return conditions;
67
+ }
68
+ /**
69
+ * Build search conditions for text search
70
+ *
71
+ * @param searchString - Text to search for
72
+ * @param properties - Properties to search in
73
+ * @returns Array of MongoDB filter objects for text search
74
+ */
75
+ static buildSearchConditions(searchString, properties) {
76
+ if (!searchString) return [];
77
+ const orConditions = [];
78
+ const searchRegex = new RegExp(searchString, "i");
79
+ for (const [key, prop] of Object.entries(properties)) {
80
+ if (prop?.dataType === "string" || typeof prop === "string") {
81
+ orConditions.push({
82
+ [key]: { $regex: searchRegex }
83
+ });
84
+ }
85
+ }
86
+ if (orConditions.length === 0) {
87
+ return [{ $text: { $search: searchString } }];
88
+ }
89
+ return orConditions;
90
+ }
91
+ /**
92
+ * Combine multiple conditions with AND operator
93
+ *
94
+ * @param conditions - Array of filter conditions
95
+ * @returns Combined filter or undefined if empty
96
+ */
97
+ static combineConditionsWithAnd(conditions) {
98
+ if (conditions.length === 0) return void 0;
99
+ if (conditions.length === 1) return conditions[0];
100
+ return { $and: conditions };
101
+ }
102
+ /**
103
+ * Combine multiple conditions with OR operator
104
+ *
105
+ * @param conditions - Array of filter conditions
106
+ * @returns Combined filter or undefined if empty
107
+ */
108
+ static combineConditionsWithOr(conditions) {
109
+ if (conditions.length === 0) return void 0;
110
+ if (conditions.length === 1) return conditions[0];
111
+ return { $or: conditions };
112
+ }
113
+ /**
114
+ * Build a complete MongoDB query from Rebase options
115
+ *
116
+ * @param options - Rebase fetch options
117
+ * @returns MongoDB filter object
118
+ */
119
+ static buildQuery(options) {
120
+ const conditions = [];
121
+ if (options.filter) {
122
+ const filterConditions = this.buildFilterConditions(options.filter);
123
+ conditions.push(...filterConditions);
124
+ }
125
+ if (options.searchString && options.properties) {
126
+ const searchConditions = this.buildSearchConditions(
127
+ options.searchString,
128
+ options.properties
129
+ );
130
+ if (searchConditions.length > 0) {
131
+ const searchFilter = this.combineConditionsWithOr(searchConditions);
132
+ if (searchFilter) {
133
+ conditions.push(searchFilter);
134
+ }
135
+ }
136
+ }
137
+ return this.combineConditionsWithAnd(conditions) ?? {};
138
+ }
139
+ /**
140
+ * Build MongoDB sort options from Rebase options
141
+ *
142
+ * @param orderBy - Field to order by
143
+ * @param order - Sort direction
144
+ * @returns MongoDB sort object
145
+ */
146
+ static buildSort(orderBy, order) {
147
+ if (!orderBy) return void 0;
148
+ return { [orderBy]: order === "desc" ? -1 : 1 };
149
+ }
150
+ }
151
+ class MongoEntityService {
152
+ constructor(db) {
153
+ this.db = db;
154
+ }
155
+ /**
156
+ * Get a MongoDB collection by its path
157
+ */
158
+ getCollection(collectionPath) {
159
+ const collectionName = collectionPath.replace(/\//g, "_");
160
+ return this.db.collection(collectionName);
161
+ }
162
+ /**
163
+ * Convert a string ID to ObjectId if it's a valid ObjectId string
164
+ */
165
+ toObjectId(id) {
166
+ if (typeof id === "string" && ObjectId.isValid(id) && id.length === 24) {
167
+ return new ObjectId(id);
168
+ }
169
+ return id;
170
+ }
171
+ /**
172
+ * Convert a MongoDB document to a Rebase Entity
173
+ */
174
+ documentToEntity(doc, path) {
175
+ const { _id, ...values } = doc;
176
+ return {
177
+ id: _id.toString(),
178
+ path,
179
+ values: this.convertFromMongoValues(values)
180
+ };
181
+ }
182
+ /**
183
+ * Convert values from MongoDB format to Rebase format
184
+ */
185
+ convertFromMongoValues(values) {
186
+ const result = {};
187
+ for (const [key, value] of Object.entries(values)) {
188
+ result[key] = this.convertFromMongoValue(value);
189
+ }
190
+ return result;
191
+ }
192
+ /**
193
+ * Convert a single value from MongoDB format
194
+ */
195
+ convertFromMongoValue(value) {
196
+ if (value === null || value === void 0) return value;
197
+ if (value instanceof ObjectId) {
198
+ return value.toString();
199
+ }
200
+ if (value instanceof Date) {
201
+ return value;
202
+ }
203
+ if (Array.isArray(value)) {
204
+ return value.map((v) => this.convertFromMongoValue(v));
205
+ }
206
+ if (typeof value === "object" && "path" in value && "id" in value) {
207
+ return {
208
+ path: value.path,
209
+ id: value.id instanceof ObjectId ? value.id.toString() : value.id
210
+ };
211
+ }
212
+ if (typeof value === "object") {
213
+ return this.convertFromMongoValues(value);
214
+ }
215
+ return value;
216
+ }
217
+ /**
218
+ * Convert values to MongoDB format for storage
219
+ */
220
+ convertToMongoValues(values) {
221
+ const result = {};
222
+ for (const [key, value] of Object.entries(values)) {
223
+ result[key] = this.convertToMongoValue(value);
224
+ }
225
+ return result;
226
+ }
227
+ /**
228
+ * Convert a single value to MongoDB format
229
+ */
230
+ convertToMongoValue(value) {
231
+ if (value === null || value === void 0) return value;
232
+ if (typeof value === "object" && value.isEntityReference?.()) {
233
+ return {
234
+ id: ObjectId.isValid(value.id) ? new ObjectId(value.id) : value.id,
235
+ path: value.path
236
+ };
237
+ }
238
+ if (value instanceof Date) {
239
+ return value;
240
+ }
241
+ if (Array.isArray(value)) {
242
+ return value.map((v) => this.convertToMongoValue(v));
243
+ }
244
+ if (typeof value === "object") {
245
+ return this.convertToMongoValues(value);
246
+ }
247
+ return value;
248
+ }
249
+ // =============================================================
250
+ // EntityRepository Implementation
251
+ // =============================================================
252
+ /**
253
+ * Fetch a single entity by ID
254
+ */
255
+ async fetchEntity(collectionPath, entityId, _databaseId) {
256
+ const collection = this.getCollection(collectionPath);
257
+ const id = this.toObjectId(entityId);
258
+ const doc = await collection.findOne({ _id: id });
259
+ if (!doc) return void 0;
260
+ return this.documentToEntity(doc, collectionPath);
261
+ }
262
+ /**
263
+ * Fetch a collection of entities with optional filtering, ordering, and pagination
264
+ */
265
+ async fetchCollection(collectionPath, options = {}) {
266
+ const collection = this.getCollection(collectionPath);
267
+ const query = MongoConditionBuilder.buildQuery({
268
+ filter: options.filter,
269
+ searchString: options.searchString,
270
+ properties: options.collection?.properties ?? {}
271
+ });
272
+ const findOptions = {};
273
+ const sort = MongoConditionBuilder.buildSort(options.orderBy, options.order);
274
+ if (sort) {
275
+ findOptions.sort = sort;
276
+ }
277
+ if (options.limit) {
278
+ findOptions.limit = options.limit;
279
+ }
280
+ if (options.startAfter !== void 0) {
281
+ findOptions.skip = Number(options.startAfter);
282
+ }
283
+ const docs = await collection.find(query, findOptions).toArray();
284
+ return docs.map((doc) => this.documentToEntity(doc, collectionPath));
285
+ }
286
+ /**
287
+ * Search entities by text
288
+ */
289
+ async searchEntities(collectionPath, searchString, options = {}) {
290
+ return this.fetchCollection(collectionPath, {
291
+ ...options,
292
+ searchString
293
+ });
294
+ }
295
+ /**
296
+ * Count entities in a collection
297
+ */
298
+ async countEntities(collectionPath, options = {}) {
299
+ const collection = this.getCollection(collectionPath);
300
+ const query = options.filter ? MongoConditionBuilder.buildQuery({ filter: options.filter }) : {};
301
+ return collection.countDocuments(query);
302
+ }
303
+ /**
304
+ * Save an entity (create or update)
305
+ */
306
+ async saveEntity(collectionPath, values, entityId, _databaseId) {
307
+ const collection = this.getCollection(collectionPath);
308
+ const mongoValues = this.convertToMongoValues(values);
309
+ if (entityId) {
310
+ const id = this.toObjectId(entityId);
311
+ await collection.updateOne(
312
+ { _id: id },
313
+ { $set: mongoValues },
314
+ { upsert: true }
315
+ );
316
+ return {
317
+ id: entityId.toString(),
318
+ path: collectionPath,
319
+ values
320
+ };
321
+ } else {
322
+ const newId = new ObjectId();
323
+ await collection.insertOne({
324
+ _id: newId,
325
+ ...mongoValues
326
+ });
327
+ return {
328
+ id: newId.toString(),
329
+ path: collectionPath,
330
+ values
331
+ };
332
+ }
333
+ }
334
+ /**
335
+ * Delete an entity by ID
336
+ */
337
+ async deleteEntity(collectionPath, entityId, _databaseId) {
338
+ const collection = this.getCollection(collectionPath);
339
+ const id = this.toObjectId(entityId);
340
+ const result = await collection.deleteOne({ _id: id });
341
+ if (result.deletedCount === 0) {
342
+ console.warn(`Entity ${entityId} not found in collection ${collectionPath}`);
343
+ }
344
+ }
345
+ /**
346
+ * Check if a field value is unique in a collection
347
+ */
348
+ async checkUniqueField(collectionPath, fieldName, value, excludeEntityId, _databaseId) {
349
+ const collection = this.getCollection(collectionPath);
350
+ const query = { [fieldName]: value };
351
+ if (excludeEntityId) {
352
+ const id = this.toObjectId(excludeEntityId);
353
+ query._id = { $ne: id };
354
+ }
355
+ const count = await collection.countDocuments(query);
356
+ return count === 0;
357
+ }
358
+ /**
359
+ * Generate a new entity ID
360
+ */
361
+ generateEntityId() {
362
+ return new ObjectId().toString();
363
+ }
364
+ }
365
+ class MongoRealtimeService {
366
+ constructor(db) {
367
+ this.db = db;
368
+ this.entityService = new MongoEntityService(db);
369
+ }
370
+ subscriptions = /* @__PURE__ */ new Map();
371
+ clients = /* @__PURE__ */ new Map();
372
+ entityService;
373
+ /**
374
+ * Get the collection name from a path
375
+ */
376
+ getCollectionName(path) {
377
+ return path.replace(/\//g, "_");
378
+ }
379
+ /**
380
+ * Subscribe to collection changes
381
+ */
382
+ subscribeToCollection(subscriptionId, config, callback) {
383
+ this.unsubscribe(subscriptionId);
384
+ const collectionName = this.getCollectionName(config.path);
385
+ const collection = this.db.collection(collectionName);
386
+ const pipeline = [];
387
+ pipeline.push({
388
+ $match: {
389
+ operationType: { $in: ["insert", "update", "replace", "delete"] }
390
+ }
391
+ });
392
+ try {
393
+ const changeStream = collection.watch(pipeline, {
394
+ fullDocument: "updateLookup"
395
+ });
396
+ const subscription = {
397
+ type: "collection",
398
+ config,
399
+ changeStream,
400
+ callback
401
+ };
402
+ this.subscriptions.set(subscriptionId, subscription);
403
+ this.fetchAndNotifyCollection(subscriptionId, config, callback);
404
+ changeStream.on("change", async (change) => {
405
+ await this.fetchAndNotifyCollection(subscriptionId, config, callback);
406
+ });
407
+ changeStream.on("error", (error) => {
408
+ console.error(`Change stream error for subscription ${subscriptionId}:`, error);
409
+ });
410
+ } catch (error) {
411
+ console.warn("Change streams not available, falling back to polling:", error);
412
+ const subscription = {
413
+ type: "collection",
414
+ config,
415
+ callback
416
+ };
417
+ this.subscriptions.set(subscriptionId, subscription);
418
+ this.fetchAndNotifyCollection(subscriptionId, config, callback);
419
+ }
420
+ }
421
+ /**
422
+ * Fetch collection and notify callback
423
+ */
424
+ async fetchAndNotifyCollection(subscriptionId, config, callback) {
425
+ try {
426
+ const entities = await this.entityService.fetchCollection(config.path, {
427
+ filter: config.filter,
428
+ orderBy: config.orderBy,
429
+ order: config.order,
430
+ limit: config.limit,
431
+ startAfter: config.startAfter,
432
+ searchString: config.searchString
433
+ });
434
+ if (callback) {
435
+ callback(entities);
436
+ }
437
+ } catch (error) {
438
+ console.error(`Error fetching collection for subscription ${subscriptionId}:`, error);
439
+ }
440
+ }
441
+ /**
442
+ * Subscribe to single entity changes
443
+ */
444
+ subscribeToEntity(subscriptionId, config, callback) {
445
+ this.unsubscribe(subscriptionId);
446
+ const collectionName = this.getCollectionName(config.path);
447
+ const collection = this.db.collection(collectionName);
448
+ const entityId = typeof config.entityId === "string" && ObjectId.isValid(config.entityId) ? new ObjectId(config.entityId) : config.entityId;
449
+ const pipeline = [
450
+ {
451
+ $match: {
452
+ "documentKey._id": entityId,
453
+ operationType: { $in: ["insert", "update", "replace", "delete"] }
454
+ }
455
+ }
456
+ ];
457
+ try {
458
+ const changeStream = collection.watch(pipeline, {
459
+ fullDocument: "updateLookup"
460
+ });
461
+ const subscription = {
462
+ type: "entity",
463
+ config,
464
+ changeStream,
465
+ callback
466
+ };
467
+ this.subscriptions.set(subscriptionId, subscription);
468
+ this.fetchAndNotifyEntity(subscriptionId, config, callback);
469
+ changeStream.on("change", async (change) => {
470
+ if (change.operationType === "delete") {
471
+ if (callback) {
472
+ callback(null);
473
+ }
474
+ } else {
475
+ await this.fetchAndNotifyEntity(subscriptionId, config, callback);
476
+ }
477
+ });
478
+ changeStream.on("error", (error) => {
479
+ console.error(`Change stream error for subscription ${subscriptionId}:`, error);
480
+ });
481
+ } catch (error) {
482
+ console.warn("Change streams not available, falling back to polling:", error);
483
+ const subscription = {
484
+ type: "entity",
485
+ config,
486
+ callback
487
+ };
488
+ this.subscriptions.set(subscriptionId, subscription);
489
+ this.fetchAndNotifyEntity(subscriptionId, config, callback);
490
+ }
491
+ }
492
+ /**
493
+ * Fetch entity and notify callback
494
+ */
495
+ async fetchAndNotifyEntity(subscriptionId, config, callback) {
496
+ try {
497
+ const entity = await this.entityService.fetchEntity(config.path, config.entityId);
498
+ if (callback) {
499
+ callback(entity || null);
500
+ }
501
+ } catch (error) {
502
+ console.error(`Error fetching entity for subscription ${subscriptionId}:`, error);
503
+ }
504
+ }
505
+ /**
506
+ * Unsubscribe from a subscription
507
+ */
508
+ unsubscribe(subscriptionId) {
509
+ const subscription = this.subscriptions.get(subscriptionId);
510
+ if (subscription) {
511
+ if (subscription.changeStream) {
512
+ subscription.changeStream.close().catch(console.error);
513
+ }
514
+ this.subscriptions.delete(subscriptionId);
515
+ }
516
+ }
517
+ /**
518
+ * Notify all relevant subscribers of an entity update
519
+ * This is called after save/delete operations to push updates
520
+ */
521
+ async notifyEntityUpdate(path, entityId, entity, _databaseId) {
522
+ for (const [subscriptionId, subscription] of this.subscriptions) {
523
+ if (subscription.type === "entity") {
524
+ const config = subscription.config;
525
+ if (config.path === path && config.entityId.toString() === entityId) {
526
+ if (subscription.callback) {
527
+ subscription.callback(entity);
528
+ }
529
+ }
530
+ } else if (subscription.type === "collection") {
531
+ const config = subscription.config;
532
+ if (config.path === path) {
533
+ await this.fetchAndNotifyCollection(subscriptionId, config, subscription.callback);
534
+ }
535
+ }
536
+ }
537
+ }
538
+ /**
539
+ * Get all active subscriptions (for debugging)
540
+ */
541
+ getSubscriptions() {
542
+ return this.subscriptions;
543
+ }
544
+ /**
545
+ * Close all subscriptions
546
+ */
547
+ async closeAll() {
548
+ for (const [subscriptionId] of this.subscriptions) {
549
+ this.unsubscribe(subscriptionId);
550
+ }
551
+ }
552
+ // =============================================================================
553
+ // WebSocket Client Management (parity with PostgreSQL RealtimeService)
554
+ // =============================================================================
555
+ /**
556
+ * Register a WebSocket client for real-time communication
557
+ */
558
+ addClient(clientId, ws) {
559
+ this.clients.set(clientId, ws);
560
+ ws.on("close", () => {
561
+ this.removeClient(clientId);
562
+ });
563
+ ws.on("error", (error) => {
564
+ console.error("WebSocket error for client", clientId, error);
565
+ this.removeClient(clientId);
566
+ });
567
+ }
568
+ /**
569
+ * Remove a WebSocket client and clean up its subscriptions
570
+ */
571
+ removeClient(clientId) {
572
+ this.clients.delete(clientId);
573
+ }
574
+ /**
575
+ * Handle an incoming WebSocket message for subscription management
576
+ */
577
+ async handleClientMessage(clientId, message, _authContext) {
578
+ const ws = this.clients.get(clientId);
579
+ if (!ws) return;
580
+ switch (message.type) {
581
+ case "subscribe_collection": {
582
+ const subscriptionId = message.payload?.subscriptionId ?? message.subscriptionId;
583
+ if (!subscriptionId) return;
584
+ this.subscribeToCollection(
585
+ subscriptionId,
586
+ {
587
+ clientId,
588
+ path: message.payload?.path,
589
+ filter: message.payload?.filter,
590
+ orderBy: message.payload?.orderBy,
591
+ order: message.payload?.order,
592
+ limit: message.payload?.limit,
593
+ startAfter: message.payload?.startAfter,
594
+ searchString: message.payload?.searchString
595
+ },
596
+ (entities) => {
597
+ ws.send(JSON.stringify({
598
+ type: "collection_update",
599
+ subscriptionId,
600
+ entities
601
+ }));
602
+ }
603
+ );
604
+ break;
605
+ }
606
+ case "subscribe_entity": {
607
+ const subscriptionId = message.payload?.subscriptionId ?? message.subscriptionId;
608
+ if (!subscriptionId) return;
609
+ this.subscribeToEntity(
610
+ subscriptionId,
611
+ {
612
+ clientId,
613
+ path: message.payload?.path,
614
+ entityId: message.payload?.entityId
615
+ },
616
+ (entity) => {
617
+ ws.send(JSON.stringify({
618
+ type: "entity_update",
619
+ subscriptionId,
620
+ entity
621
+ }));
622
+ }
623
+ );
624
+ break;
625
+ }
626
+ case "unsubscribe": {
627
+ const subscriptionId = message.payload?.subscriptionId ?? message.subscriptionId;
628
+ if (subscriptionId) {
629
+ this.unsubscribe(subscriptionId);
630
+ }
631
+ break;
632
+ }
633
+ }
634
+ }
635
+ }
636
+ function findChangedFields(oldValues, newValues) {
637
+ const changed = [];
638
+ const allKeys = /* @__PURE__ */ new Set([
639
+ ...Object.keys(oldValues),
640
+ ...Object.keys(newValues)
641
+ ]);
642
+ for (const key of allKeys) {
643
+ const oldVal = oldValues[key];
644
+ const newVal = newValues[key];
645
+ if (key.startsWith("__")) continue;
646
+ if (oldVal !== newVal) {
647
+ if (typeof oldVal === "object" && oldVal !== null && typeof newVal === "object" && newVal !== null) {
648
+ if (JSON.stringify(oldVal) !== JSON.stringify(newVal)) {
649
+ changed.push(key);
650
+ }
651
+ } else {
652
+ changed.push(key);
653
+ }
654
+ }
655
+ }
656
+ return changed.length > 0 ? changed : null;
657
+ }
658
+ const DEFAULT_RETENTION = {
659
+ maxEntries: 200,
660
+ ttlDays: 90
661
+ };
662
+ class MongoHistoryService {
663
+ constructor(db, retention) {
664
+ this.db = db;
665
+ this.retention = { ...DEFAULT_RETENTION, ...retention };
666
+ }
667
+ retention;
668
+ async recordHistory(params) {
669
+ const {
670
+ tableName,
671
+ entityId,
672
+ action,
673
+ values,
674
+ previousValues,
675
+ updatedBy
676
+ } = params;
677
+ const changedFields = previousValues && values ? findChangedFields(previousValues, values) : null;
678
+ if (action === "update" && (!changedFields || changedFields.length === 0)) {
679
+ return;
680
+ }
681
+ try {
682
+ const entry = {
683
+ id: new ObjectId().toString(),
684
+ table_name: tableName,
685
+ entity_id: String(entityId),
686
+ action,
687
+ changed_fields: changedFields,
688
+ values: values || null,
689
+ previous_values: previousValues || null,
690
+ updated_by: updatedBy || null,
691
+ updated_at: /* @__PURE__ */ new Date()
692
+ };
693
+ await this.db.collection("__rebase_history").insertOne(entry);
694
+ this.pruneHistory(String(entityId), tableName).catch((e) => {
695
+ console.error(`[HistoryService] Failed to prune history for ${tableName}/${entityId}:`, e);
696
+ });
697
+ } catch (error) {
698
+ console.error(`[HistoryService] Failed to record history for ${tableName}/${entityId}:`, error);
699
+ }
700
+ }
701
+ async pruneHistory(entityId, tableName) {
702
+ const collection = this.db.collection("__rebase_history");
703
+ const count = await collection.countDocuments({ entity_id: entityId, table_name: tableName });
704
+ if (count > this.retention.maxEntries) {
705
+ const toDelete = count - this.retention.maxEntries;
706
+ const oldestEntries = await collection.find({ entity_id: entityId, table_name: tableName }).sort({ updated_at: 1 }).limit(toDelete).toArray();
707
+ if (oldestEntries.length > 0) {
708
+ const idsToDelete = oldestEntries.map((entry) => entry._id);
709
+ await collection.deleteMany({ _id: { $in: idsToDelete } });
710
+ }
711
+ }
712
+ const cutoffDate = /* @__PURE__ */ new Date();
713
+ cutoffDate.setDate(cutoffDate.getDate() - this.retention.ttlDays);
714
+ await collection.deleteMany({
715
+ entity_id: entityId,
716
+ table_name: tableName,
717
+ updated_at: { $lt: cutoffDate }
718
+ });
719
+ }
720
+ }
721
+ const MongoHistoryService$1 = /* @__PURE__ */ Object.freeze(/* @__PURE__ */ Object.defineProperty({
722
+ __proto__: null,
723
+ MongoHistoryService,
724
+ findChangedFields
725
+ }, Symbol.toStringTag, { value: "Module" }));
726
+ class MongoDriver {
727
+ constructor(db, realtimeService, historyService) {
728
+ this.db = db;
729
+ this.entityService = new MongoEntityService(db);
730
+ this.realtimeService = realtimeService ?? new MongoRealtimeService(db);
731
+ this.historyService = historyService ?? new MongoHistoryService(db);
732
+ }
733
+ key = "mongodb";
734
+ initialised = true;
735
+ entityService;
736
+ realtimeService;
737
+ historyService;
738
+ /**
739
+ * Get the current timestamp
740
+ */
741
+ currentTime() {
742
+ return /* @__PURE__ */ new Date();
743
+ }
744
+ /**
745
+ * Fetch a collection of entities
746
+ */
747
+ async fetchCollection({
748
+ path,
749
+ collection,
750
+ filter,
751
+ limit,
752
+ startAfter,
753
+ orderBy,
754
+ searchString,
755
+ order
756
+ }) {
757
+ return this.entityService.fetchCollection(path, {
758
+ filter,
759
+ limit,
760
+ startAfter,
761
+ orderBy,
762
+ order,
763
+ searchString,
764
+ collection
765
+ });
766
+ }
767
+ /**
768
+ * Listen to collection changes
769
+ */
770
+ listenCollection({
771
+ path,
772
+ collection,
773
+ filter,
774
+ limit,
775
+ startAfter,
776
+ orderBy,
777
+ searchString,
778
+ order,
779
+ onUpdate,
780
+ onError
781
+ }) {
782
+ const subscriptionId = this.generateSubscriptionId();
783
+ const callback = (entities) => {
784
+ try {
785
+ onUpdate(entities);
786
+ } catch (error) {
787
+ console.error("Error in collection update callback:", error);
788
+ if (onError) {
789
+ onError(error instanceof Error ? error : new Error(String(error)));
790
+ }
791
+ }
792
+ };
793
+ this.realtimeService.subscribeToCollection(
794
+ subscriptionId,
795
+ {
796
+ clientId: "driver",
797
+ path,
798
+ filter,
799
+ orderBy,
800
+ order,
801
+ limit,
802
+ startAfter,
803
+ searchString
804
+ },
805
+ callback
806
+ );
807
+ return () => {
808
+ this.realtimeService.unsubscribe(subscriptionId);
809
+ };
810
+ }
811
+ /**
812
+ * Fetch a single entity
813
+ */
814
+ async fetchEntity({
815
+ path,
816
+ entityId,
817
+ databaseId,
818
+ collection
819
+ }) {
820
+ return this.entityService.fetchEntity(path, entityId, databaseId);
821
+ }
822
+ /**
823
+ * Listen to entity changes
824
+ */
825
+ listenEntity({
826
+ path,
827
+ entityId,
828
+ collection,
829
+ onUpdate,
830
+ onError
831
+ }) {
832
+ const subscriptionId = this.generateSubscriptionId();
833
+ const callback = (entity) => {
834
+ try {
835
+ onUpdate(entity);
836
+ } catch (error) {
837
+ console.error("Error in entity update callback:", error);
838
+ if (onError) {
839
+ onError(error instanceof Error ? error : new Error(String(error)));
840
+ }
841
+ }
842
+ };
843
+ this.realtimeService.subscribeToEntity(
844
+ subscriptionId,
845
+ {
846
+ clientId: "driver",
847
+ path,
848
+ entityId
849
+ },
850
+ callback
851
+ );
852
+ return () => {
853
+ this.realtimeService.unsubscribe(subscriptionId);
854
+ };
855
+ }
856
+ /**
857
+ * Save an entity (create or update)
858
+ */
859
+ async saveEntity({
860
+ path,
861
+ entityId,
862
+ values,
863
+ previousValues,
864
+ collection,
865
+ status
866
+ }) {
867
+ const isNew = status === "new" || !previousValues;
868
+ const entity = await this.entityService.saveEntity(path, values, entityId);
869
+ if (collection?.history) {
870
+ this.historyService.recordHistory({
871
+ action: isNew ? "create" : "update",
872
+ entityId: String(entity.id),
873
+ tableName: path,
874
+ values: entity.values,
875
+ previousValues: isNew ? void 0 : previousValues
876
+ }).catch((err) => {
877
+ console.error(`Failed to record history for ${path}/${entity.id}:`, err);
878
+ });
879
+ }
880
+ await this.realtimeService.notifyEntityUpdate(path, String(entity.id), entity);
881
+ return entity;
882
+ }
883
+ /**
884
+ * Delete an entity
885
+ */
886
+ async deleteEntity({
887
+ entity,
888
+ collection
889
+ }) {
890
+ await this.entityService.deleteEntity(entity.path, entity.id);
891
+ if (collection?.history) {
892
+ this.historyService.recordHistory({
893
+ action: "delete",
894
+ entityId: String(entity.id),
895
+ tableName: entity.path,
896
+ previousValues: entity.values
897
+ }).catch((err) => {
898
+ console.error(`Failed to record history for ${entity.path}/${entity.id}:`, err);
899
+ });
900
+ }
901
+ await this.realtimeService.notifyEntityUpdate(entity.path, String(entity.id), null);
902
+ }
903
+ /**
904
+ * Check if a field value is unique
905
+ */
906
+ async checkUniqueField(path, name, value, entityId, collection) {
907
+ return this.entityService.checkUniqueField(path, name, value, entityId);
908
+ }
909
+ /**
910
+ * Generate a new entity ID
911
+ */
912
+ generateEntityId(path, collection) {
913
+ return this.entityService.generateEntityId();
914
+ }
915
+ /**
916
+ * Count entities in a collection
917
+ */
918
+ async countEntities({
919
+ path,
920
+ collection,
921
+ filter
922
+ }) {
923
+ return this.entityService.countEntities(path, { filter });
924
+ }
925
+ /**
926
+ * Generate a unique subscription ID
927
+ */
928
+ generateSubscriptionId() {
929
+ return `mongo_${Date.now()}_${Math.random().toString(36).substring(2, 9)}`;
930
+ }
931
+ /**
932
+ * Check if the delegate is ready
933
+ */
934
+ isReady() {
935
+ return this.initialised;
936
+ }
937
+ /**
938
+ * Get the underlying entity service for direct access
939
+ */
940
+ getEntityService() {
941
+ return this.entityService;
942
+ }
943
+ /**
944
+ * Get the underlying realtime service for direct access
945
+ */
946
+ getRealtimeService() {
947
+ return this.realtimeService;
948
+ }
949
+ }
950
+ class MongoCollectionRegistry {
951
+ collections = /* @__PURE__ */ new Map();
952
+ /**
953
+ * Register a collection
954
+ */
955
+ register(collection) {
956
+ this.collections.set(collection.name, collection);
957
+ }
958
+ /**
959
+ * Get a collection by its path
960
+ */
961
+ getCollectionByPath(path) {
962
+ return this.collections.get(path);
963
+ }
964
+ /**
965
+ * Get all registered collections
966
+ */
967
+ getCollections() {
968
+ return Array.from(this.collections.values());
969
+ }
970
+ }
971
+ function createMongoBackend(config) {
972
+ const { connection: db, client, collections } = config;
973
+ const collectionRegistry = new MongoCollectionRegistry();
974
+ if (collections) {
975
+ collections.forEach((collection) => collectionRegistry.register(collection));
976
+ }
977
+ const entityService = new MongoEntityService(db);
978
+ const realtimeService = new MongoRealtimeService(db);
979
+ const historyService = new MongoHistoryService(db, config.historyRetention);
980
+ const driver = new MongoDriver(db, realtimeService, historyService);
981
+ const mongoConnection = new MongoDBConnection(db, client);
982
+ const admin = {
983
+ async executeAggregate(pipeline) {
984
+ const firstStage = pipeline[0];
985
+ const collName = typeof firstStage.$from === "string" ? firstStage.$from : "__admin__";
986
+ const cursor = db.collection(collName).aggregate(pipeline);
987
+ return await cursor.toArray();
988
+ },
989
+ async fetchCollectionStats(collectionName) {
990
+ const stats = await db.command({ collStats: collectionName });
991
+ return {
992
+ count: stats.count,
993
+ sizeBytes: stats.size
994
+ };
995
+ },
996
+ async fetchUnmappedTables(mappedPaths) {
997
+ const allCollections = await db.listCollections().toArray();
998
+ const names = allCollections.map((c) => c.name).filter((n) => !n.startsWith("system."));
999
+ if (!mappedPaths || mappedPaths.length === 0) return names;
1000
+ const mappedSet = new Set(mappedPaths.map((p) => p.toLowerCase()));
1001
+ return names.filter((n) => !mappedSet.has(n.toLowerCase()));
1002
+ },
1003
+ async fetchTableMetadata(collectionName) {
1004
+ const sample = await db.collection(collectionName).findOne();
1005
+ if (!sample) return {
1006
+ columns: [],
1007
+ foreignKeys: [],
1008
+ junctions: [],
1009
+ policies: []
1010
+ };
1011
+ const columns = Object.entries(sample).map(([key, value]) => ({
1012
+ column_name: key,
1013
+ data_type: typeof value,
1014
+ udt_name: typeof value,
1015
+ is_nullable: "YES",
1016
+ column_default: null,
1017
+ character_maximum_length: null
1018
+ }));
1019
+ return {
1020
+ columns,
1021
+ foreignKeys: [],
1022
+ junctions: [],
1023
+ policies: []
1024
+ };
1025
+ }
1026
+ };
1027
+ return {
1028
+ // Abstract interface implementations
1029
+ connection: mongoConnection,
1030
+ entityRepository: entityService,
1031
+ realtimeProvider: realtimeService,
1032
+ collectionRegistry,
1033
+ admin,
1034
+ // Lifecycle
1035
+ async initialize() {
1036
+ },
1037
+ async healthCheck() {
1038
+ const start = Date.now();
1039
+ try {
1040
+ await db.command({ ping: 1 });
1041
+ return {
1042
+ healthy: true,
1043
+ latencyMs: Date.now() - start
1044
+ };
1045
+ } catch {
1046
+ return {
1047
+ healthy: false,
1048
+ latencyMs: Date.now() - start
1049
+ };
1050
+ }
1051
+ },
1052
+ async destroy() {
1053
+ await client.close();
1054
+ },
1055
+ // MongoDB-specific accessors
1056
+ db,
1057
+ client,
1058
+ driver,
1059
+ entityService,
1060
+ realtimeService
1061
+ };
1062
+ }
1063
+ function createMongoDelegate(db, realtimeService, historyService) {
1064
+ const realtime = realtimeService ?? new MongoRealtimeService(db);
1065
+ const history = historyService ?? new MongoHistoryService(db);
1066
+ return new MongoDriver(db, realtime, history);
1067
+ }
1068
+ function createMongoRealtimeService(db) {
1069
+ return new MongoRealtimeService(db);
1070
+ }
1071
+ function createMongoEntityRepository(db) {
1072
+ return new MongoEntityService(db);
1073
+ }
1074
+ function isMongoBackendConfig(config) {
1075
+ return config.type === "mongodb" && typeof config.connection !== "undefined" && typeof config.client !== "undefined";
1076
+ }
1077
+ function isMongoDriverConfig(obj) {
1078
+ return typeof obj === "object" && obj !== null && "type" in obj && obj.type === "mongodb" && "connection" in obj && "client" in obj;
1079
+ }
1080
+ function toUser(doc) {
1081
+ return {
1082
+ id: doc._id || doc.id,
1083
+ email: doc.email,
1084
+ passwordHash: doc.passwordHash ?? null,
1085
+ displayName: doc.displayName ?? null,
1086
+ photoUrl: doc.photoUrl ?? null,
1087
+ emailVerified: doc.emailVerified ?? false,
1088
+ emailVerificationToken: doc.emailVerificationToken ?? null,
1089
+ emailVerificationSentAt: doc.emailVerificationSentAt ? new Date(doc.emailVerificationSentAt) : null,
1090
+ createdAt: new Date(doc.createdAt),
1091
+ updatedAt: new Date(doc.updatedAt)
1092
+ };
1093
+ }
1094
+ class MongoUserService {
1095
+ constructor(db) {
1096
+ this.db = db;
1097
+ }
1098
+ get collection() {
1099
+ return this.db.collection("rebase_users");
1100
+ }
1101
+ get identitiesCollection() {
1102
+ return this.db.collection("rebase_user_identities");
1103
+ }
1104
+ get userRolesCollection() {
1105
+ return this.db.collection("rebase_user_roles");
1106
+ }
1107
+ get rolesCollection() {
1108
+ return this.db.collection("rebase_roles");
1109
+ }
1110
+ async createUser(data) {
1111
+ const id = new ObjectId().toString();
1112
+ const now = /* @__PURE__ */ new Date();
1113
+ const doc = {
1114
+ _id: id,
1115
+ id,
1116
+ email: data.email.toLowerCase(),
1117
+ passwordHash: data.passwordHash ?? null,
1118
+ displayName: data.displayName ?? null,
1119
+ photoUrl: data.photoUrl ?? null,
1120
+ emailVerified: data.emailVerified ?? false,
1121
+ createdAt: now,
1122
+ updatedAt: now
1123
+ };
1124
+ await this.collection.insertOne(doc);
1125
+ return toUser(doc);
1126
+ }
1127
+ async getUserById(id) {
1128
+ const doc = await this.collection.findOne({ id });
1129
+ return doc ? toUser(doc) : null;
1130
+ }
1131
+ async getUserByEmail(email) {
1132
+ const doc = await this.collection.findOne({ email: email.toLowerCase() });
1133
+ return doc ? toUser(doc) : null;
1134
+ }
1135
+ async getUserByIdentity(provider, providerId) {
1136
+ const identity = await this.identitiesCollection.findOne({ provider, providerId });
1137
+ if (!identity) return null;
1138
+ return this.getUserById(identity.userId);
1139
+ }
1140
+ async getUserIdentities(userId) {
1141
+ const docs = await this.identitiesCollection.find({ userId }).toArray();
1142
+ return docs.map((doc) => ({
1143
+ id: doc.id,
1144
+ userId: doc.userId,
1145
+ provider: doc.provider,
1146
+ providerId: doc.providerId,
1147
+ profileData: doc.profileData ?? null,
1148
+ createdAt: new Date(doc.createdAt),
1149
+ updatedAt: new Date(doc.updatedAt)
1150
+ }));
1151
+ }
1152
+ async linkUserIdentity(userId, provider, providerId, profileData) {
1153
+ const now = /* @__PURE__ */ new Date();
1154
+ await this.identitiesCollection.updateOne(
1155
+ { provider, providerId },
1156
+ {
1157
+ $setOnInsert: {
1158
+ _id: new ObjectId().toString(),
1159
+ id: new ObjectId().toString(),
1160
+ userId,
1161
+ provider,
1162
+ providerId,
1163
+ createdAt: now
1164
+ },
1165
+ $set: {
1166
+ profileData: profileData ?? null,
1167
+ updatedAt: now
1168
+ }
1169
+ },
1170
+ { upsert: true }
1171
+ );
1172
+ }
1173
+ async updateUser(id, data) {
1174
+ const updateData = { ...data, updatedAt: /* @__PURE__ */ new Date() };
1175
+ if (typeof updateData.email === "string") updateData.email = updateData.email.toLowerCase();
1176
+ await this.collection.updateOne({ id }, { $set: updateData });
1177
+ return this.getUserById(id);
1178
+ }
1179
+ async deleteUser(id) {
1180
+ await this.collection.deleteOne({ id });
1181
+ await this.identitiesCollection.deleteMany({ userId: id });
1182
+ await this.userRolesCollection.deleteMany({ userId: id });
1183
+ }
1184
+ async listUsers() {
1185
+ const docs = await this.collection.find().toArray();
1186
+ return docs.map(toUser);
1187
+ }
1188
+ async listUsersPaginated(options) {
1189
+ const limit = options?.limit ?? 25;
1190
+ const offset = options?.offset ?? 0;
1191
+ const search = options?.search?.trim() || "";
1192
+ const orderBy = options?.orderBy || "createdAt";
1193
+ const orderDir = options?.orderDir || "desc";
1194
+ const roleId = options?.roleId;
1195
+ const query = {};
1196
+ if (search) {
1197
+ query.$or = [
1198
+ { email: { $regex: search, $options: "i" } },
1199
+ { displayName: { $regex: search, $options: "i" } }
1200
+ ];
1201
+ }
1202
+ if (roleId) {
1203
+ const userRoles = await this.userRolesCollection.find({ roleId }).toArray();
1204
+ const userIds = userRoles.map((ur) => ur.userId);
1205
+ query.id = { $in: userIds };
1206
+ }
1207
+ const sort = {};
1208
+ sort[orderBy] = orderDir === "asc" ? 1 : -1;
1209
+ const total = await this.collection.countDocuments(query);
1210
+ const docs = await this.collection.find(query).sort(sort).skip(offset).limit(limit).toArray();
1211
+ return {
1212
+ users: docs.map(toUser),
1213
+ total,
1214
+ limit,
1215
+ offset
1216
+ };
1217
+ }
1218
+ async updatePassword(id, passwordHash) {
1219
+ await this.collection.updateOne(
1220
+ { id },
1221
+ { $set: { passwordHash, updatedAt: /* @__PURE__ */ new Date() } }
1222
+ );
1223
+ }
1224
+ async setEmailVerified(id, verified) {
1225
+ await this.collection.updateOne(
1226
+ { id },
1227
+ { $set: { emailVerified: verified, emailVerificationToken: null, updatedAt: /* @__PURE__ */ new Date() } }
1228
+ );
1229
+ }
1230
+ async setVerificationToken(id, token) {
1231
+ await this.collection.updateOne(
1232
+ { id },
1233
+ { $set: { emailVerificationToken: token, emailVerificationSentAt: token ? /* @__PURE__ */ new Date() : null, updatedAt: /* @__PURE__ */ new Date() } }
1234
+ );
1235
+ }
1236
+ async getUserByVerificationToken(token) {
1237
+ const doc = await this.collection.findOne({ emailVerificationToken: token });
1238
+ return doc ? toUser(doc) : null;
1239
+ }
1240
+ async getUserRoles(userId) {
1241
+ const userRoles = await this.userRolesCollection.find({ userId }).toArray();
1242
+ const roleIds = userRoles.map((ur) => ur.roleId);
1243
+ if (roleIds.length === 0) return [];
1244
+ const roles = await this.rolesCollection.find({ id: { $in: roleIds } }).toArray();
1245
+ return roles.map((r) => ({
1246
+ id: r.id,
1247
+ name: r.name,
1248
+ isAdmin: r.isAdmin ?? false,
1249
+ defaultPermissions: r.defaultPermissions ?? null,
1250
+ collectionPermissions: r.collectionPermissions ?? null,
1251
+ config: r.config ?? null
1252
+ }));
1253
+ }
1254
+ async getUserRoleIds(userId) {
1255
+ const userRoles = await this.userRolesCollection.find({ userId }).toArray();
1256
+ return userRoles.map((ur) => ur.roleId);
1257
+ }
1258
+ async setUserRoles(userId, roleIds) {
1259
+ await this.userRolesCollection.deleteMany({ userId });
1260
+ if (roleIds.length > 0) {
1261
+ const docs = roleIds.map((roleId) => ({
1262
+ _id: new ObjectId().toString(),
1263
+ userId,
1264
+ roleId
1265
+ }));
1266
+ await this.userRolesCollection.insertMany(docs);
1267
+ }
1268
+ }
1269
+ async assignDefaultRole(userId, roleId) {
1270
+ await this.userRolesCollection.updateOne(
1271
+ { userId, roleId },
1272
+ { $setOnInsert: { _id: new ObjectId().toString(), userId, roleId } },
1273
+ { upsert: true }
1274
+ );
1275
+ }
1276
+ async getUserWithRoles(userId) {
1277
+ const user = await this.getUserById(userId);
1278
+ if (!user) return null;
1279
+ const roles = await this.getUserRoles(userId);
1280
+ return { user, roles };
1281
+ }
1282
+ }
1283
+ class MongoRoleService {
1284
+ constructor(db) {
1285
+ this.db = db;
1286
+ }
1287
+ get collection() {
1288
+ return this.db.collection("rebase_roles");
1289
+ }
1290
+ async getRoleById(id) {
1291
+ const doc = await this.collection.findOne({ id });
1292
+ if (!doc) return null;
1293
+ return {
1294
+ id: doc.id,
1295
+ name: doc.name,
1296
+ isAdmin: doc.isAdmin ?? false,
1297
+ defaultPermissions: doc.defaultPermissions ?? null,
1298
+ collectionPermissions: doc.collectionPermissions ?? null,
1299
+ config: doc.config ?? null
1300
+ };
1301
+ }
1302
+ async listRoles() {
1303
+ const docs = await this.collection.find().sort({ name: 1 }).toArray();
1304
+ return docs.map((doc) => ({
1305
+ id: doc.id,
1306
+ name: doc.name,
1307
+ isAdmin: doc.isAdmin ?? false,
1308
+ defaultPermissions: doc.defaultPermissions ?? null,
1309
+ collectionPermissions: doc.collectionPermissions ?? null,
1310
+ config: doc.config ?? null
1311
+ }));
1312
+ }
1313
+ async createRole(data) {
1314
+ const doc = {
1315
+ _id: data.id,
1316
+ id: data.id,
1317
+ name: data.name,
1318
+ isAdmin: data.isAdmin ?? false,
1319
+ defaultPermissions: data.defaultPermissions ?? null,
1320
+ collectionPermissions: data.collectionPermissions ?? null,
1321
+ config: data.config ?? null
1322
+ };
1323
+ await this.collection.insertOne(doc);
1324
+ return { ...doc };
1325
+ }
1326
+ async updateRole(id, data) {
1327
+ await this.collection.updateOne({ id }, { $set: data });
1328
+ return this.getRoleById(id);
1329
+ }
1330
+ async deleteRole(id) {
1331
+ await this.collection.deleteOne({ id });
1332
+ await this.db.collection("rebase_user_roles").deleteMany({ roleId: id });
1333
+ }
1334
+ }
1335
+ class MongoRefreshTokenService {
1336
+ constructor(db) {
1337
+ this.db = db;
1338
+ }
1339
+ get collection() {
1340
+ return this.db.collection("rebase_refresh_tokens");
1341
+ }
1342
+ async createToken(userId, tokenHash, expiresAt, userAgent, ipAddress) {
1343
+ const safeUserAgent = userAgent || "";
1344
+ const safeIpAddress = ipAddress || "";
1345
+ await this.collection.deleteMany({
1346
+ userId,
1347
+ userAgent: safeUserAgent,
1348
+ ipAddress: safeIpAddress
1349
+ });
1350
+ await this.collection.insertOne({
1351
+ _id: new ObjectId().toString(),
1352
+ id: new ObjectId().toString(),
1353
+ userId,
1354
+ tokenHash,
1355
+ expiresAt,
1356
+ createdAt: /* @__PURE__ */ new Date(),
1357
+ userAgent: safeUserAgent,
1358
+ ipAddress: safeIpAddress
1359
+ });
1360
+ }
1361
+ async findByHash(tokenHash) {
1362
+ const doc = await this.collection.findOne({ tokenHash });
1363
+ if (!doc) return null;
1364
+ return {
1365
+ id: doc.id,
1366
+ userId: doc.userId,
1367
+ tokenHash: doc.tokenHash,
1368
+ expiresAt: new Date(doc.expiresAt),
1369
+ createdAt: new Date(doc.createdAt),
1370
+ userAgent: doc.userAgent,
1371
+ ipAddress: doc.ipAddress
1372
+ };
1373
+ }
1374
+ async deleteByHash(tokenHash) {
1375
+ await this.collection.deleteOne({ tokenHash });
1376
+ }
1377
+ async deleteAllForUser(userId) {
1378
+ await this.collection.deleteMany({ userId });
1379
+ }
1380
+ async listForUser(userId) {
1381
+ const docs = await this.collection.find({ userId }).sort({ createdAt: 1 }).toArray();
1382
+ return docs.map((doc) => ({
1383
+ id: doc.id,
1384
+ userId: doc.userId,
1385
+ tokenHash: doc.tokenHash,
1386
+ expiresAt: new Date(doc.expiresAt),
1387
+ createdAt: new Date(doc.createdAt),
1388
+ userAgent: doc.userAgent,
1389
+ ipAddress: doc.ipAddress
1390
+ }));
1391
+ }
1392
+ async deleteById(id, userId) {
1393
+ await this.collection.deleteOne({ id, userId });
1394
+ }
1395
+ }
1396
+ class MongoPasswordResetTokenService {
1397
+ constructor(db) {
1398
+ this.db = db;
1399
+ }
1400
+ get collection() {
1401
+ return this.db.collection("rebase_password_reset_tokens");
1402
+ }
1403
+ async createToken(userId, tokenHash, expiresAt) {
1404
+ await this.collection.deleteMany({ userId, usedAt: null });
1405
+ await this.collection.insertOne({
1406
+ _id: new ObjectId().toString(),
1407
+ userId,
1408
+ tokenHash,
1409
+ expiresAt,
1410
+ usedAt: null
1411
+ });
1412
+ }
1413
+ async findValidByHash(tokenHash) {
1414
+ const doc = await this.collection.findOne({
1415
+ tokenHash,
1416
+ usedAt: null,
1417
+ expiresAt: { $gt: /* @__PURE__ */ new Date() }
1418
+ });
1419
+ if (!doc) return null;
1420
+ return {
1421
+ userId: doc.userId,
1422
+ expiresAt: new Date(doc.expiresAt)
1423
+ };
1424
+ }
1425
+ async markAsUsed(tokenHash) {
1426
+ await this.collection.updateOne(
1427
+ { tokenHash },
1428
+ { $set: { usedAt: /* @__PURE__ */ new Date() } }
1429
+ );
1430
+ }
1431
+ async deleteAllForUser(userId) {
1432
+ await this.collection.deleteMany({ userId });
1433
+ }
1434
+ async deleteExpired() {
1435
+ await this.collection.deleteMany({ expiresAt: { $lt: /* @__PURE__ */ new Date() } });
1436
+ }
1437
+ }
1438
+ class MongoTokenRepository {
1439
+ constructor(db) {
1440
+ this.db = db;
1441
+ this.refreshTokenService = new MongoRefreshTokenService(db);
1442
+ this.passwordResetTokenService = new MongoPasswordResetTokenService(db);
1443
+ }
1444
+ refreshTokenService;
1445
+ passwordResetTokenService;
1446
+ async createRefreshToken(userId, tokenHash, expiresAt, userAgent, ipAddress) {
1447
+ await this.refreshTokenService.createToken(userId, tokenHash, expiresAt, userAgent, ipAddress);
1448
+ }
1449
+ async findRefreshTokenByHash(tokenHash) {
1450
+ return this.refreshTokenService.findByHash(tokenHash);
1451
+ }
1452
+ async deleteRefreshToken(tokenHash) {
1453
+ await this.refreshTokenService.deleteByHash(tokenHash);
1454
+ }
1455
+ async deleteAllRefreshTokensForUser(userId) {
1456
+ await this.refreshTokenService.deleteAllForUser(userId);
1457
+ }
1458
+ async listRefreshTokensForUser(userId) {
1459
+ return this.refreshTokenService.listForUser(userId);
1460
+ }
1461
+ async deleteRefreshTokenById(id, userId) {
1462
+ await this.refreshTokenService.deleteById(id, userId);
1463
+ }
1464
+ async createPasswordResetToken(userId, tokenHash, expiresAt) {
1465
+ await this.passwordResetTokenService.createToken(userId, tokenHash, expiresAt);
1466
+ }
1467
+ async findValidPasswordResetToken(tokenHash) {
1468
+ return this.passwordResetTokenService.findValidByHash(tokenHash);
1469
+ }
1470
+ async markPasswordResetTokenUsed(tokenHash) {
1471
+ await this.passwordResetTokenService.markAsUsed(tokenHash);
1472
+ }
1473
+ async deleteAllPasswordResetTokensForUser(userId) {
1474
+ await this.passwordResetTokenService.deleteAllForUser(userId);
1475
+ }
1476
+ async deleteExpiredTokens() {
1477
+ await this.passwordResetTokenService.deleteExpired();
1478
+ }
1479
+ }
1480
+ class MongoAuthRepository {
1481
+ constructor(db) {
1482
+ this.db = db;
1483
+ this.userService = new MongoUserService(db);
1484
+ this.roleService = new MongoRoleService(db);
1485
+ this.tokenRepository = new MongoTokenRepository(db);
1486
+ }
1487
+ userService;
1488
+ roleService;
1489
+ tokenRepository;
1490
+ async createUser(data) {
1491
+ return this.userService.createUser(data);
1492
+ }
1493
+ async getUserById(id) {
1494
+ return this.userService.getUserById(id);
1495
+ }
1496
+ async getUserByEmail(email) {
1497
+ return this.userService.getUserByEmail(email);
1498
+ }
1499
+ async getUserByIdentity(provider, providerId) {
1500
+ return this.userService.getUserByIdentity(provider, providerId);
1501
+ }
1502
+ async getUserIdentities(userId) {
1503
+ return this.userService.getUserIdentities(userId);
1504
+ }
1505
+ async linkUserIdentity(userId, provider, providerId, profileData) {
1506
+ return this.userService.linkUserIdentity(userId, provider, providerId, profileData);
1507
+ }
1508
+ async updateUser(id, data) {
1509
+ return this.userService.updateUser(id, data);
1510
+ }
1511
+ async deleteUser(id) {
1512
+ await this.userService.deleteUser(id);
1513
+ }
1514
+ async listUsers() {
1515
+ return this.userService.listUsers();
1516
+ }
1517
+ async listUsersPaginated(options) {
1518
+ return this.userService.listUsersPaginated(options);
1519
+ }
1520
+ async updatePassword(id, passwordHash) {
1521
+ await this.userService.updatePassword(id, passwordHash);
1522
+ }
1523
+ async setEmailVerified(id, verified) {
1524
+ await this.userService.setEmailVerified(id, verified);
1525
+ }
1526
+ async setVerificationToken(id, token) {
1527
+ await this.userService.setVerificationToken(id, token);
1528
+ }
1529
+ async getUserByVerificationToken(token) {
1530
+ return this.userService.getUserByVerificationToken(token);
1531
+ }
1532
+ async getUserRoles(userId) {
1533
+ return this.userService.getUserRoles(userId);
1534
+ }
1535
+ async getUserRoleIds(userId) {
1536
+ return this.userService.getUserRoleIds(userId);
1537
+ }
1538
+ async setUserRoles(userId, roleIds) {
1539
+ await this.userService.setUserRoles(userId, roleIds);
1540
+ }
1541
+ async assignDefaultRole(userId, roleId) {
1542
+ await this.userService.assignDefaultRole(userId, roleId);
1543
+ }
1544
+ async getUserWithRoles(userId) {
1545
+ return this.userService.getUserWithRoles(userId);
1546
+ }
1547
+ async getRoleById(id) {
1548
+ return this.roleService.getRoleById(id);
1549
+ }
1550
+ async listRoles() {
1551
+ return this.roleService.listRoles();
1552
+ }
1553
+ async createRole(data) {
1554
+ return this.roleService.createRole(data);
1555
+ }
1556
+ async updateRole(id, data) {
1557
+ return this.roleService.updateRole(id, data);
1558
+ }
1559
+ async deleteRole(id) {
1560
+ await this.roleService.deleteRole(id);
1561
+ }
1562
+ async createRefreshToken(userId, tokenHash, expiresAt, userAgent, ipAddress) {
1563
+ await this.tokenRepository.createRefreshToken(userId, tokenHash, expiresAt, userAgent, ipAddress);
1564
+ }
1565
+ async findRefreshTokenByHash(tokenHash) {
1566
+ return this.tokenRepository.findRefreshTokenByHash(tokenHash);
1567
+ }
1568
+ async deleteRefreshToken(tokenHash) {
1569
+ await this.tokenRepository.deleteRefreshToken(tokenHash);
1570
+ }
1571
+ async deleteAllRefreshTokensForUser(userId) {
1572
+ await this.tokenRepository.deleteAllRefreshTokensForUser(userId);
1573
+ }
1574
+ async listRefreshTokensForUser(userId) {
1575
+ return this.tokenRepository.listRefreshTokensForUser(userId);
1576
+ }
1577
+ async deleteRefreshTokenById(id, userId) {
1578
+ await this.tokenRepository.deleteRefreshTokenById(id, userId);
1579
+ }
1580
+ async createPasswordResetToken(userId, tokenHash, expiresAt) {
1581
+ await this.tokenRepository.createPasswordResetToken(userId, tokenHash, expiresAt);
1582
+ }
1583
+ async findValidPasswordResetToken(tokenHash) {
1584
+ return this.tokenRepository.findValidPasswordResetToken(tokenHash);
1585
+ }
1586
+ async markPasswordResetTokenUsed(tokenHash) {
1587
+ await this.tokenRepository.markPasswordResetTokenUsed(tokenHash);
1588
+ }
1589
+ async deleteAllPasswordResetTokensForUser(userId) {
1590
+ await this.tokenRepository.deleteAllPasswordResetTokensForUser(userId);
1591
+ }
1592
+ async deleteExpiredTokens() {
1593
+ await this.tokenRepository.deleteExpiredTokens();
1594
+ }
1595
+ }
1596
+ function createMongoBootstrapper(mongoConfig) {
1597
+ let cachedAdmin;
1598
+ return {
1599
+ type: "mongodb",
1600
+ async initializeDriver(config) {
1601
+ const { collections } = config;
1602
+ const registry = new MongoCollectionRegistry();
1603
+ if (collections) {
1604
+ collections.forEach((collection) => registry.register(collection));
1605
+ }
1606
+ const db = mongoConfig.connection;
1607
+ const client = mongoConfig.client;
1608
+ try {
1609
+ await db.command({ ping: 1 });
1610
+ } catch (err) {
1611
+ console.error("❌ Failed to connect to MongoDB:", err);
1612
+ }
1613
+ const realtimeService = new MongoRealtimeService(db);
1614
+ const driver = new MongoDriver(db, realtimeService);
1615
+ const internals = {
1616
+ db,
1617
+ client,
1618
+ registry,
1619
+ realtimeService,
1620
+ driver
1621
+ };
1622
+ return {
1623
+ driver,
1624
+ realtimeProvider: realtimeService,
1625
+ collectionRegistry: registry,
1626
+ internals
1627
+ };
1628
+ },
1629
+ async initializeAuth(config, driverResult) {
1630
+ const internals = driverResult.internals;
1631
+ const db = internals.db;
1632
+ const { ensureAuthCollectionsExist } = await import("./ensure-collections-CNrcwVgY.js");
1633
+ await ensureAuthCollectionsExist(db);
1634
+ const { createEmailService } = await import("@rebasepro/server-core");
1635
+ const authConfig = config;
1636
+ let emailService;
1637
+ if (authConfig?.email) {
1638
+ emailService = createEmailService(authConfig.email);
1639
+ }
1640
+ const userService = new MongoUserService(db);
1641
+ const roleService = new MongoRoleService(db);
1642
+ const authRepository = new MongoAuthRepository(db);
1643
+ return {
1644
+ userService,
1645
+ roleService,
1646
+ authRepository,
1647
+ emailService
1648
+ };
1649
+ },
1650
+ async initializeHistory(config, driverResult) {
1651
+ const historyConfig = config;
1652
+ if (!historyConfig) return void 0;
1653
+ const internals = driverResult.internals;
1654
+ const db = internals.db;
1655
+ const { ensureHistoryCollectionExists } = await import("./ensure-history-collection-DBIiwmCm.js");
1656
+ await ensureHistoryCollectionExists(db);
1657
+ const { MongoHistoryService: MongoHistoryService2 } = await Promise.resolve().then(() => MongoHistoryService$1);
1658
+ const retention = typeof historyConfig === "object" && historyConfig !== null ? historyConfig.retention : void 0;
1659
+ const historyService = new MongoHistoryService2(db, retention ? { ttlDays: retention } : void 0);
1660
+ return { historyService };
1661
+ },
1662
+ async initializeRealtime(_config, driverResult) {
1663
+ const internals = driverResult.internals;
1664
+ return internals.realtimeService;
1665
+ },
1666
+ getAdmin(driverResult) {
1667
+ const internals = driverResult.internals;
1668
+ const db = internals.db;
1669
+ const admin = {
1670
+ async executeAggregate(pipeline) {
1671
+ const firstStage = pipeline[0];
1672
+ const collName = firstStage?.$from ?? "__admin__";
1673
+ const cursor = db.collection(collName).aggregate(pipeline);
1674
+ return await cursor.toArray();
1675
+ },
1676
+ async fetchCollectionStats(collectionName) {
1677
+ const stats = await db.command({ collStats: collectionName });
1678
+ return { count: stats.count, sizeBytes: stats.size };
1679
+ },
1680
+ async fetchUnmappedTables(mappedPaths) {
1681
+ const allCollections = await db.listCollections().toArray();
1682
+ const names = allCollections.map((c) => c.name).filter((n) => !n.startsWith("system."));
1683
+ if (!mappedPaths || mappedPaths.length === 0) return names;
1684
+ const mappedSet = new Set(mappedPaths.map((p) => p.toLowerCase()));
1685
+ return names.filter((n) => !mappedSet.has(n.toLowerCase()));
1686
+ },
1687
+ async fetchTableMetadata(collectionName) {
1688
+ const sample = await db.collection(collectionName).findOne();
1689
+ if (!sample) return { columns: [], foreignKeys: [], junctions: [], policies: [] };
1690
+ const columns = Object.entries(sample).map(([key, value]) => ({
1691
+ column_name: key,
1692
+ data_type: typeof value,
1693
+ udt_name: typeof value,
1694
+ is_nullable: "YES",
1695
+ column_default: null,
1696
+ character_maximum_length: null
1697
+ }));
1698
+ return { columns, foreignKeys: [], junctions: [], policies: [] };
1699
+ }
1700
+ };
1701
+ cachedAdmin = admin;
1702
+ return admin;
1703
+ },
1704
+ mountRoutes() {
1705
+ },
1706
+ async initializeWebsockets(server, realtimeService, driver, config) {
1707
+ const { createMongoWebSocket } = await import("./websocket-BZlPuJrt.js");
1708
+ createMongoWebSocket(
1709
+ server,
1710
+ realtimeService,
1711
+ driver,
1712
+ config,
1713
+ cachedAdmin
1714
+ );
1715
+ }
1716
+ };
1717
+ }
1718
+ export {
1719
+ MongoCollectionRegistry,
1720
+ MongoConditionBuilder,
1721
+ MongoDBConnection,
1722
+ MongoDriver,
1723
+ MongoEntityService,
1724
+ MongoRealtimeService,
1725
+ createMongoBackend,
1726
+ createMongoBootstrapper,
1727
+ createMongoDBConnection,
1728
+ createMongoDelegate,
1729
+ createMongoEntityRepository,
1730
+ createMongoRealtimeService,
1731
+ isMongoBackendConfig,
1732
+ isMongoDriverConfig
1733
+ };
1734
+ //# sourceMappingURL=index.es.js.map