@ambiten/core 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 (304) hide show
  1. package/LICENSE +21 -0
  2. package/README.md +247 -0
  3. package/bin/bootstrap.js +26 -0
  4. package/dist/ambiten-cache/ambitenCache.d.ts +64 -0
  5. package/dist/ambiten-cache/ambitenCache.d.ts.map +1 -0
  6. package/dist/ambiten-cache/ambitenCache.js +127 -0
  7. package/dist/ambiten-cache/index.d.ts +2 -0
  8. package/dist/ambiten-cache/index.d.ts.map +1 -0
  9. package/dist/ambiten-cache/index.js +4 -0
  10. package/dist/browser.d.ts +32 -0
  11. package/dist/browser.d.ts.map +1 -0
  12. package/dist/browser.js +37 -0
  13. package/dist/cli/ambiten-core-cli.d.ts +4 -0
  14. package/dist/cli/ambiten-core-cli.d.ts.map +1 -0
  15. package/dist/cli/ambiten-core-cli.js +41 -0
  16. package/dist/cli/buildInteractiveConfig.d.ts +4 -0
  17. package/dist/cli/buildInteractiveConfig.d.ts.map +1 -0
  18. package/dist/cli/buildInteractiveConfig.js +198 -0
  19. package/dist/cli/index.d.ts +5 -0
  20. package/dist/cli/index.d.ts.map +1 -0
  21. package/dist/cli/index.js +7 -0
  22. package/dist/cli/prompt.d.ts +10 -0
  23. package/dist/cli/prompt.d.ts.map +1 -0
  24. package/dist/cli/prompt.js +48 -0
  25. package/dist/cli/types.d.ts +11 -0
  26. package/dist/cli/types.d.ts.map +1 -0
  27. package/dist/cli/types.js +2 -0
  28. package/dist/config/ambiten.config.schema.json +278 -0
  29. package/dist/config/index.d.ts +2 -0
  30. package/dist/config/index.d.ts.map +1 -0
  31. package/dist/config/index.js +4 -0
  32. package/dist/config/loadAmbitenConfig.d.ts +3 -0
  33. package/dist/config/loadAmbitenConfig.d.ts.map +1 -0
  34. package/dist/config/loadAmbitenConfig.js +131 -0
  35. package/dist/context/ambitenContext.d.ts +35 -0
  36. package/dist/context/ambitenContext.d.ts.map +1 -0
  37. package/dist/context/ambitenContext.js +147 -0
  38. package/dist/context/helpers/runManualTransaction.d.ts +3 -0
  39. package/dist/context/helpers/runManualTransaction.d.ts.map +1 -0
  40. package/dist/context/helpers/runManualTransaction.js +22 -0
  41. package/dist/context/helpers/transactionSession.d.ts +9 -0
  42. package/dist/context/helpers/transactionSession.d.ts.map +1 -0
  43. package/dist/context/helpers/transactionSession.js +8 -0
  44. package/dist/context/index.d.ts +4 -0
  45. package/dist/context/index.d.ts.map +1 -0
  46. package/dist/context/index.js +6 -0
  47. package/dist/debug/debugLog.d.ts +2 -0
  48. package/dist/debug/debugLog.d.ts.map +1 -0
  49. package/dist/debug/debugLog.js +23 -0
  50. package/dist/debug/index.d.ts +2 -0
  51. package/dist/debug/index.d.ts.map +1 -0
  52. package/dist/debug/index.js +4 -0
  53. package/dist/gc/ambitenGC.d.ts +49 -0
  54. package/dist/gc/ambitenGC.d.ts.map +1 -0
  55. package/dist/gc/ambitenGC.js +138 -0
  56. package/dist/gc/gcCron.browser.d.ts +2 -0
  57. package/dist/gc/gcCron.browser.d.ts.map +1 -0
  58. package/dist/gc/gcCron.browser.js +9 -0
  59. package/dist/gc/gcCron.node.d.ts +19 -0
  60. package/dist/gc/gcCron.node.d.ts.map +1 -0
  61. package/dist/gc/gcCron.node.js +47 -0
  62. package/dist/gc/gcManager.d.ts +37 -0
  63. package/dist/gc/gcManager.d.ts.map +1 -0
  64. package/dist/gc/gcManager.js +62 -0
  65. package/dist/gc/index.d.ts +5 -0
  66. package/dist/gc/index.d.ts.map +1 -0
  67. package/dist/gc/index.js +7 -0
  68. package/dist/graphql/ambitenGraphQL.d.ts +24 -0
  69. package/dist/graphql/ambitenGraphQL.d.ts.map +1 -0
  70. package/dist/graphql/ambitenGraphQL.js +215 -0
  71. package/dist/graphql/index.d.ts +2 -0
  72. package/dist/graphql/index.d.ts.map +1 -0
  73. package/dist/graphql/index.js +4 -0
  74. package/dist/index-browser.js +25 -0
  75. package/dist/index-browser.js.map +1 -0
  76. package/dist/index-cli.js +26 -0
  77. package/dist/index-cli.js.map +1 -0
  78. package/dist/index.d.ts +30 -0
  79. package/dist/index.d.ts.map +1 -0
  80. package/dist/index.js +25 -0
  81. package/dist/index.js.map +1 -0
  82. package/dist/init-cli/generate.project.d.ts +9 -0
  83. package/dist/init-cli/generate.project.d.ts.map +1 -0
  84. package/dist/init-cli/generate.project.js +38 -0
  85. package/dist/instrumentation/index.d.ts +3 -0
  86. package/dist/instrumentation/index.d.ts.map +1 -0
  87. package/dist/instrumentation/index.js +5 -0
  88. package/dist/instrumentation/measureQuery.browser.d.ts +3 -0
  89. package/dist/instrumentation/measureQuery.browser.d.ts.map +1 -0
  90. package/dist/instrumentation/measureQuery.browser.js +6 -0
  91. package/dist/instrumentation/measureQueryWithErrors.d.ts +11 -0
  92. package/dist/instrumentation/measureQueryWithErrors.d.ts.map +1 -0
  93. package/dist/instrumentation/measureQueryWithErrors.js +90 -0
  94. package/dist/lib-core/ambitenClient.d.ts +115 -0
  95. package/dist/lib-core/ambitenClient.d.ts.map +1 -0
  96. package/dist/lib-core/ambitenClient.js +537 -0
  97. package/dist/lib-core/ambitenModelFactory.d.ts +979 -0
  98. package/dist/lib-core/ambitenModelFactory.d.ts.map +1 -0
  99. package/dist/lib-core/ambitenModelFactory.js +3984 -0
  100. package/dist/lib-core/ambitenSchema.d.ts +126 -0
  101. package/dist/lib-core/ambitenSchema.d.ts.map +1 -0
  102. package/dist/lib-core/ambitenSchema.js +247 -0
  103. package/dist/lib-core/bootstrap/ambitenBootstrap.d.ts +38 -0
  104. package/dist/lib-core/bootstrap/ambitenBootstrap.d.ts.map +1 -0
  105. package/dist/lib-core/bootstrap/ambitenBootstrap.js +381 -0
  106. package/dist/lib-core/bootstrap/index.d.ts +2 -0
  107. package/dist/lib-core/bootstrap/index.d.ts.map +1 -0
  108. package/dist/lib-core/bootstrap/index.js +4 -0
  109. package/dist/lib-core/index.d.ts +5 -0
  110. package/dist/lib-core/index.d.ts.map +1 -0
  111. package/dist/lib-core/index.js +7 -0
  112. package/dist/middleware/authorization/auth.d.ts +22 -0
  113. package/dist/middleware/authorization/auth.d.ts.map +1 -0
  114. package/dist/middleware/authorization/auth.js +37 -0
  115. package/dist/middleware/index.d.ts +4 -0
  116. package/dist/middleware/index.d.ts.map +1 -0
  117. package/dist/middleware/index.js +6 -0
  118. package/dist/middleware/rbac/rbacMiddleware.d.ts +103 -0
  119. package/dist/middleware/rbac/rbacMiddleware.d.ts.map +1 -0
  120. package/dist/middleware/rbac/rbacMiddleware.js +246 -0
  121. package/dist/middleware/rbac/rbacTypes.d.ts +4 -0
  122. package/dist/middleware/rbac/rbacTypes.d.ts.map +1 -0
  123. package/dist/middleware/rbac/rbacTypes.js +8 -0
  124. package/dist/plugins/index.d.ts +3 -0
  125. package/dist/plugins/index.d.ts.map +1 -0
  126. package/dist/plugins/index.js +5 -0
  127. package/dist/plugins/softDelete/applySoftDelete.d.ts +5 -0
  128. package/dist/plugins/softDelete/applySoftDelete.d.ts.map +1 -0
  129. package/dist/plugins/softDelete/applySoftDelete.js +139 -0
  130. package/dist/plugins/softDelete/types.d.ts +14 -0
  131. package/dist/plugins/softDelete/types.d.ts.map +1 -0
  132. package/dist/plugins/softDelete/types.js +2 -0
  133. package/dist/redis-manager/index.d.ts +2 -0
  134. package/dist/redis-manager/index.d.ts.map +1 -0
  135. package/dist/redis-manager/index.js +4 -0
  136. package/dist/redis-manager/redisClient.d.ts +32 -0
  137. package/dist/redis-manager/redisClient.d.ts.map +1 -0
  138. package/dist/redis-manager/redisClient.js +146 -0
  139. package/dist/tanancy/MultiTenantManager.d.ts +98 -0
  140. package/dist/tanancy/MultiTenantManager.d.ts.map +1 -0
  141. package/dist/tanancy/MultiTenantManager.js +190 -0
  142. package/dist/tanancy/TenantContext.d.ts +31 -0
  143. package/dist/tanancy/TenantContext.d.ts.map +1 -0
  144. package/dist/tanancy/TenantContext.js +59 -0
  145. package/dist/tanancy/TenantModelResolver.d.ts +10 -0
  146. package/dist/tanancy/TenantModelResolver.d.ts.map +1 -0
  147. package/dist/tanancy/TenantModelResolver.js +114 -0
  148. package/dist/tanancy/index.d.ts +5 -0
  149. package/dist/tanancy/index.d.ts.map +1 -0
  150. package/dist/tanancy/index.js +7 -0
  151. package/dist/tanancy/init/initMultiTenancy.d.ts +29 -0
  152. package/dist/tanancy/init/initMultiTenancy.d.ts.map +1 -0
  153. package/dist/tanancy/init/initMultiTenancy.js +62 -0
  154. package/dist/templates/generateDefaultConfigContent.d.ts +10 -0
  155. package/dist/templates/generateDefaultConfigContent.d.ts.map +1 -0
  156. package/dist/templates/generateDefaultConfigContent.js +108 -0
  157. package/dist/templates/generateGCManagerFile.d.ts +2 -0
  158. package/dist/templates/generateGCManagerFile.d.ts.map +1 -0
  159. package/dist/templates/generateGCManagerFile.js +39 -0
  160. package/dist/templates/generateGCRunnerFile.d.ts +2 -0
  161. package/dist/templates/generateGCRunnerFile.d.ts.map +1 -0
  162. package/dist/templates/generateGCRunnerFile.js +25 -0
  163. package/dist/templates/generateMainEntry.d.ts +3 -0
  164. package/dist/templates/generateMainEntry.d.ts.map +1 -0
  165. package/dist/templates/generateMainEntry.js +24 -0
  166. package/dist/templates/index.d.ts +6 -0
  167. package/dist/templates/index.d.ts.map +1 -0
  168. package/dist/templates/index.js +8 -0
  169. package/dist/templates/scaffold/structureGenerator.d.ts +4 -0
  170. package/dist/templates/scaffold/structureGenerator.d.ts.map +1 -0
  171. package/dist/templates/scaffold/structureGenerator.js +193 -0
  172. package/dist/types/GCConfig.d.ts +7 -0
  173. package/dist/types/GCConfig.d.ts.map +1 -0
  174. package/dist/types/GCConfig.js +2 -0
  175. package/dist/types/ambiten-runtime-type.d.ts +24 -0
  176. package/dist/types/ambiten-runtime-type.d.ts.map +1 -0
  177. package/dist/types/ambiten-runtime-type.js +2 -0
  178. package/dist/types/ambiten.client.type.d.ts +136 -0
  179. package/dist/types/ambiten.client.type.d.ts.map +1 -0
  180. package/dist/types/ambiten.client.type.js +3 -0
  181. package/dist/types/ambiten.model.type.d.ts +135 -0
  182. package/dist/types/ambiten.model.type.d.ts.map +1 -0
  183. package/dist/types/ambiten.model.type.js +4 -0
  184. package/dist/types/ambitenConfig.d.ts +103 -0
  185. package/dist/types/ambitenConfig.d.ts.map +1 -0
  186. package/dist/types/ambitenConfig.js +3 -0
  187. package/dist/types/bootstrapClient.type.d.ts +11 -0
  188. package/dist/types/bootstrapClient.type.d.ts.map +1 -0
  189. package/dist/types/bootstrapClient.type.js +2 -0
  190. package/dist/types/db.provider.d.ts +66 -0
  191. package/dist/types/db.provider.d.ts.map +1 -0
  192. package/dist/types/db.provider.js +2 -0
  193. package/dist/types/document.d.ts +7 -0
  194. package/dist/types/document.d.ts.map +1 -0
  195. package/dist/types/document.js +2 -0
  196. package/dist/types/event.type.d.ts +6 -0
  197. package/dist/types/event.type.d.ts.map +1 -0
  198. package/dist/types/event.type.js +27 -0
  199. package/dist/types/graphql.type.d.ts +22 -0
  200. package/dist/types/graphql.type.d.ts.map +1 -0
  201. package/dist/types/graphql.type.js +2 -0
  202. package/dist/types/index.d.ts +15 -0
  203. package/dist/types/index.d.ts.map +1 -0
  204. package/dist/types/index.js +17 -0
  205. package/dist/types/logger.types.d.ts +15 -0
  206. package/dist/types/logger.types.d.ts.map +1 -0
  207. package/dist/types/logger.types.js +3 -0
  208. package/dist/types/middleware/types.d.ts +28 -0
  209. package/dist/types/middleware/types.d.ts.map +1 -0
  210. package/dist/types/middleware/types.js +2 -0
  211. package/dist/types/result.utils.types.d.ts +7 -0
  212. package/dist/types/result.utils.types.d.ts.map +1 -0
  213. package/dist/types/result.utils.types.js +2 -0
  214. package/dist/types/schema.type.d.ts +23 -0
  215. package/dist/types/schema.type.d.ts.map +1 -0
  216. package/dist/types/schema.type.js +10 -0
  217. package/dist/types/user.type.d.ts +11 -0
  218. package/dist/types/user.type.d.ts.map +1 -0
  219. package/dist/types/user.type.js +2 -0
  220. package/dist/utils/AuthUtils.d.ts +15 -0
  221. package/dist/utils/AuthUtils.d.ts.map +1 -0
  222. package/dist/utils/AuthUtils.js +26 -0
  223. package/dist/utils/ModelRegistry.d.ts +15 -0
  224. package/dist/utils/ModelRegistry.d.ts.map +1 -0
  225. package/dist/utils/ModelRegistry.js +35 -0
  226. package/dist/utils/banner.d.ts +2 -0
  227. package/dist/utils/banner.d.ts.map +1 -0
  228. package/dist/utils/banner.js +20 -0
  229. package/dist/utils/builders/createModel.d.ts +37 -0
  230. package/dist/utils/builders/createModel.d.ts.map +1 -0
  231. package/dist/utils/builders/createModel.js +38 -0
  232. package/dist/utils/builders/getTenantDb.d.ts +12 -0
  233. package/dist/utils/builders/getTenantDb.d.ts.map +1 -0
  234. package/dist/utils/builders/getTenantDb.js +25 -0
  235. package/dist/utils/builders/index.d.ts +4 -0
  236. package/dist/utils/builders/index.d.ts.map +1 -0
  237. package/dist/utils/builders/index.js +6 -0
  238. package/dist/utils/builders/schema.d.ts +22 -0
  239. package/dist/utils/builders/schema.d.ts.map +1 -0
  240. package/dist/utils/builders/schema.js +26 -0
  241. package/dist/utils/cacheWithRedis.d.ts +27 -0
  242. package/dist/utils/cacheWithRedis.d.ts.map +1 -0
  243. package/dist/utils/cacheWithRedis.js +22 -0
  244. package/dist/utils/castId.d.ts +5 -0
  245. package/dist/utils/castId.d.ts.map +1 -0
  246. package/dist/utils/castId.js +52 -0
  247. package/dist/utils/color-palatte.d.ts +4 -0
  248. package/dist/utils/color-palatte.d.ts.map +1 -0
  249. package/dist/utils/color-palatte.js +24 -0
  250. package/dist/utils/configureAmbitenContext.d.ts +13 -0
  251. package/dist/utils/configureAmbitenContext.d.ts.map +1 -0
  252. package/dist/utils/configureAmbitenContext.js +35 -0
  253. package/dist/utils/detect-package-manager.d.ts +5 -0
  254. package/dist/utils/detect-package-manager.d.ts.map +1 -0
  255. package/dist/utils/detect-package-manager.js +59 -0
  256. package/dist/utils/ensureModelNameSafe.d.ts +12 -0
  257. package/dist/utils/ensureModelNameSafe.d.ts.map +1 -0
  258. package/dist/utils/ensureModelNameSafe.js +28 -0
  259. package/dist/utils/ensureRedis.d.ts +7 -0
  260. package/dist/utils/ensureRedis.d.ts.map +1 -0
  261. package/dist/utils/ensureRedis.js +40 -0
  262. package/dist/utils/error/ambitenError-handler.d.ts +24 -0
  263. package/dist/utils/error/ambitenError-handler.d.ts.map +1 -0
  264. package/dist/utils/error/ambitenError-handler.js +39 -0
  265. package/dist/utils/error/errorTypes.d.ts +27 -0
  266. package/dist/utils/error/errorTypes.d.ts.map +1 -0
  267. package/dist/utils/error/errorTypes.js +30 -0
  268. package/dist/utils/error/index.d.ts +3 -0
  269. package/dist/utils/error/index.d.ts.map +1 -0
  270. package/dist/utils/error/index.js +5 -0
  271. package/dist/utils/eventOptions.d.ts +38 -0
  272. package/dist/utils/eventOptions.d.ts.map +1 -0
  273. package/dist/utils/eventOptions.js +130 -0
  274. package/dist/utils/events.d.ts +5 -0
  275. package/dist/utils/events.d.ts.map +1 -0
  276. package/dist/utils/events.js +7 -0
  277. package/dist/utils/index.d.ts +23 -0
  278. package/dist/utils/index.d.ts.map +1 -0
  279. package/dist/utils/index.js +25 -0
  280. package/dist/utils/invalidateTenantCache.d.ts +18 -0
  281. package/dist/utils/invalidateTenantCache.d.ts.map +1 -0
  282. package/dist/utils/invalidateTenantCache.js +27 -0
  283. package/dist/utils/logger.d.ts +3 -0
  284. package/dist/utils/logger.d.ts.map +1 -0
  285. package/dist/utils/logger.js +27 -0
  286. package/dist/utils/modelLoader.d.ts +3 -0
  287. package/dist/utils/modelLoader.d.ts.map +1 -0
  288. package/dist/utils/modelLoader.js +41 -0
  289. package/dist/utils/resolveAmbitenOption.d.ts +2 -0
  290. package/dist/utils/resolveAmbitenOption.d.ts.map +1 -0
  291. package/dist/utils/resolveAmbitenOption.js +10 -0
  292. package/dist/utils/resolveRuntimeConfig.d.ts +22 -0
  293. package/dist/utils/resolveRuntimeConfig.d.ts.map +1 -0
  294. package/dist/utils/resolveRuntimeConfig.js +33 -0
  295. package/dist/utils/scaffoldLoger.d.ts +11 -0
  296. package/dist/utils/scaffoldLoger.d.ts.map +1 -0
  297. package/dist/utils/scaffoldLoger.js +68 -0
  298. package/dist/utils/symbols.d.ts +4 -0
  299. package/dist/utils/symbols.d.ts.map +1 -0
  300. package/dist/utils/symbols.js +6 -0
  301. package/dist/utils/time.d.ts +5 -0
  302. package/dist/utils/time.d.ts.map +1 -0
  303. package/dist/utils/time.js +39 -0
  304. package/package.json +180 -0
@@ -0,0 +1,537 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.AmbitenClient = void 0;
4
+ exports.createAmbitenClientModule = createAmbitenClientModule;
5
+ /* eslint-disable @typescript-eslint/no-require-imports */
6
+ const mongodb_1 = require("mongodb");
7
+ require("dotenv/config");
8
+ const utils_1 = require("../utils");
9
+ const tanancy_1 = require("../tanancy");
10
+ const context_1 = require("../context");
11
+ const AmbitenSymbol = Symbol.for('Ambiten:default');
12
+ /**
13
+ * AmbitenClient is a MongoDB client wrapper that provides a simplified interface
14
+ * for connecting to and interacting with MongoDB databases.
15
+ */
16
+ class AmbitenClient {
17
+ _opts;
18
+ _uri;
19
+ _client;
20
+ _db;
21
+ collectionRef;
22
+ _connected = false;
23
+ _defaultDbName;
24
+ _overrideDbName;
25
+ static instances = new Map();
26
+ static defaultUri = 'mongodb://127.0.0.1:27017';
27
+ constructor(_opts) {
28
+ this._opts = _opts;
29
+ this._uri = _opts.uri || process.env.MONGO_URI || AmbitenClient.defaultUri;
30
+ this._defaultDbName =
31
+ _opts?.options?.dbName ||
32
+ process.env.DB_NAME ||
33
+ 'Ambiten_default_db';
34
+ this._client = new mongodb_1.MongoClient(this._uri, {
35
+ directConnection: true,
36
+ minPoolSize: 5,
37
+ maxPoolSize: 50,
38
+ serverSelectionTimeoutMS: 5000
39
+ });
40
+ this._db = this._client.db(this._opts.options?.dbName);
41
+ this.ensureMongoDependency();
42
+ }
43
+ static init(opts) {
44
+ const key = String(AmbitenSymbol);
45
+ const existing = this.instances.get(key);
46
+ if (existing) {
47
+ return existing;
48
+ }
49
+ const client = createAmbitenClientModule({
50
+ uri: opts?.uri ?? this.defaultUri ?? process.env.MONGO_URI,
51
+ options: { dbName: opts?.options?.dbName },
52
+ tenantResolver: opts?.tenantResolver
53
+ });
54
+ this.instances.set(key, client);
55
+ return client;
56
+ }
57
+ ensureMongoDependency() {
58
+ try {
59
+ const { MongoClient } = require('mongodb');
60
+ void MongoClient;
61
+ }
62
+ catch {
63
+ console.error('\n❌ Missing peer dependency: "mongodb".\n' +
64
+ 'Please install it in your project before continuing:\n\n' +
65
+ ' npm i mongodb\n');
66
+ process.exit(1);
67
+ }
68
+ }
69
+ /**
70
+ * Resolution order:
71
+ * 1. explicit ctx.db
72
+ * 2. tenant-aware db resolution
73
+ * 3. explicit ctx.dbName on base client
74
+ * 4. mutable override dbName
75
+ * 5. default dbName
76
+ */
77
+ async db(ctx) {
78
+ if (ctx?.db) {
79
+ return ctx.db;
80
+ }
81
+ if (ctx?.tenantId) {
82
+ const resolver = this._opts.tenantResolver;
83
+ if (!resolver) {
84
+ throw new Error('Multi-tenancy not enabled. Provide tenantResolver to AmbitenClient or avoid passing tenantId.');
85
+ }
86
+ const tenantClient = await resolver.getClient(ctx.tenantId);
87
+ if (!tenantClient) {
88
+ throw new Error(`Tenant "${ctx.tenantId}" is not registered.`);
89
+ }
90
+ const resolvedTenantDbName = ctx.dbName ??
91
+ tanancy_1.MultiTenantManager.getTenantDbName(ctx.tenantId) ??
92
+ this._defaultDbName;
93
+ return tenantClient.db(resolvedTenantDbName);
94
+ }
95
+ if (!this._client || !this._connected) {
96
+ const message = 'AmbitenClient not connected. call connect() first.';
97
+ throw (0, utils_1.createAmbitenError)(utils_1.ErrorType.CONNECTION_ERROR, message, {
98
+ details: {
99
+ operation: 'db'
100
+ }
101
+ });
102
+ }
103
+ if (ctx?.dbName) {
104
+ return this._client.db(ctx.dbName);
105
+ }
106
+ if (this._overrideDbName) {
107
+ return this._client.db(this._overrideDbName);
108
+ }
109
+ return this._client.db(this._defaultDbName);
110
+ }
111
+ static async db(ctx) {
112
+ return this.init().db(ctx);
113
+ }
114
+ validateUri(uri) {
115
+ if (!uri || typeof uri !== 'string') {
116
+ const message = 'Missing MongoDB URI. Set MONGODB_URI (or pass uri explicitly).';
117
+ throw (0, utils_1.createAmbitenError)(utils_1.ErrorType.VALIDATION_ERROR, message, {
118
+ details: {
119
+ operation: 'validateUri',
120
+ providedUri: uri,
121
+ }
122
+ });
123
+ }
124
+ if (!/^mongodb(\+srv)?:\/\//.test(uri)) {
125
+ const message = `Invalid MongoDB URI "${uri}". It must start with "mongodb://" or "mongodb+srv://".`;
126
+ throw (0, utils_1.createAmbitenError)(utils_1.ErrorType.VALIDATION_ERROR, message, {
127
+ details: {
128
+ operation: 'validateUri',
129
+ providedUri: uri,
130
+ }
131
+ });
132
+ }
133
+ }
134
+ async connect() {
135
+ this.validateUri(this._opts.uri);
136
+ if (!this._client) {
137
+ this._client = new mongodb_1.MongoClient(this._opts.uri);
138
+ }
139
+ if (!this._connected) {
140
+ await this._client.connect();
141
+ this._connected = true;
142
+ }
143
+ return this;
144
+ }
145
+ async client(ctx) {
146
+ if (ctx?.tenantId) {
147
+ const resolver = this._opts.tenantResolver;
148
+ if (!resolver) {
149
+ throw new Error('Multi-tenancy not enabled. Provide tenantResolver to AmbitenClient or avoid passing tenantId.');
150
+ }
151
+ const tenantClient = await resolver.getClient(ctx.tenantId);
152
+ if (!tenantClient) {
153
+ throw new Error(`Tenant "${ctx.tenantId}" is not registered.`);
154
+ }
155
+ return tenantClient;
156
+ }
157
+ if (!this._client) {
158
+ throw new Error('Client not initialized. Call `connect()` first.');
159
+ }
160
+ return this._client;
161
+ }
162
+ async useCollection(collectionName) {
163
+ if (!collectionName || typeof collectionName !== 'string' || !collectionName.trim()) {
164
+ throw new Error('Collection name is required.');
165
+ }
166
+ if (!this._client) {
167
+ throw new Error('Client not initialized. Call `connect()` first.');
168
+ }
169
+ const scope = this.resolveClientScope({ collectionName });
170
+ const db = this._client.db(scope.dbName);
171
+ if (!db || typeof db.collection !== 'function') {
172
+ throw new Error('Database name is required in client options.');
173
+ }
174
+ const collection = db.collection(scope.collectionName);
175
+ this.collectionRef = collection;
176
+ return collection;
177
+ }
178
+ async collection(collectionName, ctx) {
179
+ const db = await this.db(ctx);
180
+ return db.collection(collectionName);
181
+ }
182
+ async getCollection(collectionName, ctx) {
183
+ if (!this._client || typeof this._client.db !== 'function') {
184
+ return {
185
+ toString: () => collectionName
186
+ };
187
+ }
188
+ return this.collection(collectionName, ctx);
189
+ }
190
+ async getClusterInfo() {
191
+ if (!this._client) {
192
+ throw new Error('Client not initialized. Call `connect()` first.');
193
+ }
194
+ const dbName = this._opts?.options?.dbName;
195
+ if (!dbName) {
196
+ throw new Error('Database name is required in client options.');
197
+ }
198
+ const helloResult = await this._client
199
+ .db(dbName)
200
+ .admin()
201
+ .command({ hello: 1 });
202
+ if (helloResult?.msg === 'isdbgrid') {
203
+ console.log('MongoDB is running in a sharded cluster.');
204
+ return { type: 'sharded' };
205
+ }
206
+ if (helloResult?.setName || helloResult?.hosts) {
207
+ console.log('MongoDB is running as a replica set.');
208
+ return {
209
+ type: 'replicaSet',
210
+ setName: helloResult.setName,
211
+ hosts: helloResult.hosts
212
+ };
213
+ }
214
+ console.log('MongoDB is running as a standalone instance.');
215
+ return { type: 'standalone' };
216
+ }
217
+ /**
218
+ * Resolves database + session + runtime binding
219
+ */
220
+ static async resolveRuntime() {
221
+ const ctx = context_1.AmbitenContext.get();
222
+ if (!ctx?.tenantId) {
223
+ throw new Error("Tenant not resolved in context.");
224
+ }
225
+ const tenant = tanancy_1.MultiTenantManager.getTenant(ctx.tenantId);
226
+ if (!tenant) {
227
+ throw new Error(`Tenant not found: ${ctx.tenantId}`);
228
+ }
229
+ const db = this.resolveDbFromTenant(tenant, ctx);
230
+ return {
231
+ db,
232
+ session: ctx?.session,
233
+ };
234
+ }
235
+ /**
236
+ * Mutable legacy helper. Prefer withDatabase() or withScope() in request-safe flows.
237
+ */
238
+ async useDatabase(dbName) {
239
+ if (!dbName) {
240
+ throw new Error('Database name is required.');
241
+ }
242
+ const client = await this.client();
243
+ this._overrideDbName = dbName;
244
+ return {
245
+ db: client.db(dbName),
246
+ client
247
+ };
248
+ }
249
+ withDatabase(dbName) {
250
+ return {
251
+ db: async (ctx) => {
252
+ const merged = { ...ctx, dbName: ctx?.dbName ?? dbName };
253
+ return this.db(merged);
254
+ },
255
+ connect: async () => {
256
+ await this.connect();
257
+ return this;
258
+ },
259
+ client: async (ctx) => {
260
+ const merged = { ...ctx, dbName: ctx?.dbName ?? dbName };
261
+ return this.client(merged);
262
+ },
263
+ collection: async (collectionName, ctx) => {
264
+ const merged = { ...ctx, dbName: ctx?.dbName ?? dbName };
265
+ return this.collection(collectionName, merged);
266
+ },
267
+ startSession: async (ctx) => {
268
+ const merged = {
269
+ ...ctx, dbName: ctx?.dbName ?? dbName, session: ctx?.session
270
+ };
271
+ return this.startSession(merged);
272
+ },
273
+ close: async () => {
274
+ await this.close();
275
+ }
276
+ };
277
+ }
278
+ /**
279
+ * Resolves the active database name.
280
+ *
281
+ * @param overrideDbName - Optional database override.
282
+ * @returns The resolved database name.
283
+ * @throws {Error} When no database name can be resolved.
284
+ */
285
+ resolveDbName(overrideDbName) {
286
+ return this.resolveClientScope({ dbName: overrideDbName }).dbName;
287
+ }
288
+ /**
289
+ * Resolves the active client execution scope by combining explicit method
290
+ * arguments, active Ambiten runtime context, and client-level defaults.
291
+ *
292
+ * Resolution priority:
293
+ * 1. Explicit method arguments
294
+ * 2. Active Ambiten runtime context
295
+ * 3. Client configuration
296
+ * 4. Client defaults
297
+ *
298
+ * This method does not mutate runtime context or client configuration.
299
+ *
300
+ * @param input - Optional scope overrides for database, collection, and session.
301
+ * @returns The resolved execution scope for client-level operations.
302
+ * @throws {Error} When no database name can be resolved.
303
+ */
304
+ resolveClientScope(input = {}) {
305
+ const ctx = context_1.AmbitenContext.get();
306
+ const dbName = input.dbName ??
307
+ ctx.dbName ??
308
+ this._opts?.options?.dbName ??
309
+ this._defaultDbName;
310
+ if (!dbName) {
311
+ throw new Error('Database name is required in client options.');
312
+ }
313
+ const collectionName = input.collectionName ??
314
+ ctx.collectionName;
315
+ return {
316
+ tenantId: ctx.tenantId,
317
+ requestId: ctx.requestId,
318
+ dbName,
319
+ collectionName: collectionName?.trim() || undefined,
320
+ session: input.session ?? ctx.session
321
+ };
322
+ }
323
+ static resolveDbFromTenant(tenant, ctx) {
324
+ if (!tenant?.client) {
325
+ throw new Error(`Tenant "${ctx?.tenantId}" has no MongoDB client.`);
326
+ }
327
+ const dbName = ctx?.dbName ?? tenant.dbName;
328
+ if (!dbName) {
329
+ throw new Error(`Database name not resolved for tenant "${ctx?.tenantId}".`);
330
+ }
331
+ return tenant.client.db(dbName);
332
+ }
333
+ ;
334
+ async withContext(context, callback) {
335
+ return context_1.AmbitenContext.run({
336
+ tenantId: context.tenantId,
337
+ requestId: context.requestId,
338
+ dbName: context.dbName,
339
+ collectionName: context.collectionName,
340
+ session: context.session
341
+ }, callback);
342
+ }
343
+ logWithContext(level, message, meta = {}) {
344
+ const ctx = context_1.AmbitenContext.get();
345
+ const enrichedMeta = {
346
+ requestId: ctx.requestId,
347
+ tenantId: ctx.tenantId,
348
+ ...ctx.loggerMeta,
349
+ ...meta
350
+ };
351
+ this._opts.options?.config?.logger?.[level]?.(message, enrichedMeta);
352
+ }
353
+ withTenant(tenantId) {
354
+ return {
355
+ db: async (ctx) => {
356
+ const merged = { ...ctx, tenantId: ctx?.tenantId ?? tenantId };
357
+ return this.db(merged);
358
+ },
359
+ connect: async () => {
360
+ await this.connect();
361
+ return this;
362
+ },
363
+ client: async (ctx) => {
364
+ const merged = { ...ctx, tenantId: ctx?.tenantId ?? tenantId };
365
+ return this.client(merged);
366
+ },
367
+ collection: async (collectionName, ctx) => {
368
+ const merged = { ...ctx, tenantId: ctx?.tenantId ?? tenantId };
369
+ return this.collection(collectionName, merged);
370
+ },
371
+ startSession: async (ctx) => {
372
+ const merged = { ...ctx, tenantId: ctx.tenantId ?? tenantId };
373
+ return this.startSession(merged);
374
+ },
375
+ close: async () => {
376
+ await this.close();
377
+ }
378
+ };
379
+ }
380
+ withScope(scope) {
381
+ return {
382
+ db: async (ctx) => {
383
+ const merged = {
384
+ ...ctx,
385
+ tenantId: ctx?.tenantId ?? scope.tenantId,
386
+ dbName: ctx?.dbName ?? scope.dbName
387
+ };
388
+ return this.db(merged);
389
+ },
390
+ connect: async () => {
391
+ await this.connect();
392
+ return this;
393
+ },
394
+ client: async (ctx) => {
395
+ const merged = {
396
+ ...ctx,
397
+ tenantId: ctx?.tenantId ?? scope.tenantId,
398
+ dbName: ctx?.dbName ?? scope.dbName
399
+ };
400
+ return this.client(merged);
401
+ },
402
+ collection: async (collectionName, ctx) => {
403
+ const merged = {
404
+ ...ctx,
405
+ tenantId: ctx?.tenantId ?? scope.tenantId,
406
+ dbName: ctx?.dbName ?? scope.dbName
407
+ };
408
+ return this.collection(collectionName, merged);
409
+ },
410
+ startSession: async (ctx) => {
411
+ const merged = {
412
+ ...ctx,
413
+ tenantId: ctx?.tenantId ?? scope.tenantId,
414
+ dbName: ctx?.dbName ?? scope.dbName
415
+ };
416
+ return this.startSession(merged);
417
+ },
418
+ close: async () => {
419
+ await this.close();
420
+ }
421
+ };
422
+ }
423
+ resetDatabase() {
424
+ this._overrideDbName = undefined;
425
+ }
426
+ async startSession(ctx) {
427
+ const client = await this.client(ctx);
428
+ return client.startSession();
429
+ }
430
+ async dropCollection(collectionName, ctx) {
431
+ if (!this._client && !ctx?.db) {
432
+ throw (0, utils_1.createAmbitenError)(utils_1.ErrorType.CONNECTION_ERROR, 'Client not initialized. Call `connect()` first.', {
433
+ details: {
434
+ operation: 'dropCollection',
435
+ providedCollectionName: collectionName
436
+ }
437
+ });
438
+ }
439
+ const resolvedCollectionName = collectionName?.trim() ||
440
+ this.collectionRef?.collectionName;
441
+ if (!resolvedCollectionName) {
442
+ throw (0, utils_1.createAmbitenError)(utils_1.ErrorType.VALIDATION_ERROR, 'Collection name is required.', {
443
+ details: {
444
+ operation: 'dropCollection',
445
+ providedCollectionName: collectionName
446
+ }
447
+ });
448
+ }
449
+ const db = ctx?.db ?? this._client.db(this.resolveDbName(ctx?.dbName));
450
+ await db.collection(resolvedCollectionName).drop();
451
+ }
452
+ async dropDatabase(ctx) {
453
+ if (!this._client && !ctx?.db) {
454
+ throw (0, utils_1.createAmbitenError)(utils_1.ErrorType.CONNECTION_ERROR, 'Client not initialized. Call `connect()` first.', {
455
+ details: {
456
+ operation: 'dropDatabase'
457
+ }
458
+ });
459
+ }
460
+ const db = ctx?.db ??
461
+ this._client.db(this.resolveDbName(ctx?.dbName));
462
+ const result = await db.dropDatabase();
463
+ return result === undefined ? true : result;
464
+ }
465
+ async close() {
466
+ if (this._client) {
467
+ await this._client.close?.();
468
+ }
469
+ this._client = null;
470
+ this._db = null;
471
+ this._connected = false;
472
+ console.log('[info]: Disconnected from MongoDB');
473
+ }
474
+ async disconnect() {
475
+ await this.close();
476
+ }
477
+ isConnected() {
478
+ return this._connected;
479
+ }
480
+ static handleTopologyEvent(event) {
481
+ if (event instanceof mongodb_1.TopologyOpeningEvent) {
482
+ console.log(`Topology opened: ${event.topologyId}`);
483
+ }
484
+ else if (event instanceof mongodb_1.TopologyClosedEvent) {
485
+ console.log(`Topology closed: ${event.topologyId}`);
486
+ }
487
+ else {
488
+ console.warn(`[warning]: Unknown topology event: ${event}`);
489
+ }
490
+ }
491
+ ;
492
+ static async handleLogBatch(batch, transporter) {
493
+ if (!Array.isArray(batch) || batch.length === 0) {
494
+ console.warn('[warning]: Received an empty log batch or invalid format.');
495
+ return;
496
+ }
497
+ const ctx = context_1.AmbitenContext.get();
498
+ this.handleTopologyEvent(batch[0]);
499
+ const remaining = batch.slice(1);
500
+ if (remaining.length === 0)
501
+ return;
502
+ if (!transporter) {
503
+ console.warn(`[warning]: No transporter provided; ${remaining.length} topology event(s) will not be processed.`);
504
+ return;
505
+ }
506
+ const writes = remaining.map((event) => {
507
+ const eventName = event.constructor?.name ?? 'TopologyEvent';
508
+ const eventType = eventName.toLowerCase().includes('opening')
509
+ ? 'opening'
510
+ : eventName.toLowerCase().includes('closed')
511
+ ? 'closed'
512
+ : 'unknown';
513
+ const message = `Topology event: ${eventName}`;
514
+ return transporter.write({
515
+ level: 'info',
516
+ timestamp: new Date().toISOString(),
517
+ message,
518
+ source: 'AmbitenTopology',
519
+ context: {
520
+ requestId: ctx?.requestId,
521
+ tenantId: ctx?.tenantId,
522
+ collectionName: ctx?.collectionName,
523
+ dbName: ctx?.dbName,
524
+ },
525
+ meta: {
526
+ eventType,
527
+ topologyId: event.topologyId,
528
+ },
529
+ }, message);
530
+ });
531
+ await Promise.all(writes);
532
+ }
533
+ }
534
+ exports.AmbitenClient = AmbitenClient;
535
+ function createAmbitenClientModule(opts) {
536
+ return new AmbitenClient(opts);
537
+ }