@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,381 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.AmbitenBootstrapFactory = void 0;
4
+ const config_1 = require("../../config");
5
+ const logger_1 = require("@ambiten/logger");
6
+ const index_1 = require("../index");
7
+ const __1 = require("../..");
8
+ const redis_manager_1 = require("../../redis-manager");
9
+ const utils_1 = require("../../utils");
10
+ const tanancy_1 = require("../../tanancy");
11
+ const gc_1 = require("../../gc");
12
+ const invalidateTenantCache_1 = require("../../utils/invalidateTenantCache");
13
+ /**
14
+ * AmbitenBootstrap is the main entry point for initializing
15
+ * and managing the Ambiten application stack when you opt for the CLI.
16
+ * It handles MongoDB, Redis, and GraphQL setup,
17
+ * along with custom hooks for post-connection logic.
18
+ * @example
19
+ *
20
+ * ```bash
21
+ * npx Ambiten-core my-project
22
+ * cd my-project
23
+ * ```
24
+ *
25
+ * This will create a new Ambiten project in the 'my-project' directory.
26
+ * You can then customize the configuration file and start using Ambiten in your application.
27
+ *
28
+ * ---
29
+ *
30
+ * Add flags as needed:
31
+ *
32
+ * ```bash
33
+ * npx Ambiten init my-app --with-graphql --multi-tenant --with-redis
34
+ * cd my-app
35
+ * ```
36
+ * This will create a new Ambiten project with Redis caching, GraphQL support, and multi-tenancy enabled.
37
+ * enabling them in the configuration file.
38
+ *
39
+ * ---
40
+ *
41
+ * You can also use AmbitenBootstrap programmatically in your application:
42
+ * ```ts
43
+ * @example
44
+ * import { AmbitenBootstrapFactory } from '@Ambiten/core';
45
+ * async function start() {
46
+ * const Ambiten = await AmbitenBootstrapFactory.create();
47
+ * const db = Ambiten.getMongoClient();
48
+ * await db.connect();
49
+ * const graphql = await Ambiten.getGraphQL();
50
+ * // You can now use the GraphQL instance to generate schema or start a server
51
+ * // or perform other GraphQL related operations
52
+ * graphql.generateSchema();
53
+ * Ambiten.getRedisClient();
54
+ * }
55
+ * start();
56
+ * ```
57
+ *
58
+ *
59
+ * @param {string} [configFilePathOrObject] - Optional path to a custom configuration file or a config object.
60
+ * If not provided, it defaults to 'Ambiten.config.json'.
61
+ * @returns {Promise<void>} - A promise that resolves when the initialization is complete.
62
+ *
63
+ * // Now you can use Ambiten.getMongoClient(), Ambiten.getRedisClient(), etc.
64
+ */
65
+ class AmbitenBootstrap {
66
+ config;
67
+ provider;
68
+ model;
69
+ schema;
70
+ graphql;
71
+ gc;
72
+ logger;
73
+ adapter;
74
+ onConnectHooks = [];
75
+ connectCallbacks = [];
76
+ isConnected;
77
+ constructor(adapter) {
78
+ this.adapter = adapter;
79
+ }
80
+ onConnect(callback) {
81
+ if (!this.isConnected) {
82
+ callback();
83
+ return;
84
+ }
85
+ this.connectCallbacks.push(callback);
86
+ }
87
+ /**
88
+ * Initializes the Ambiten application stack.
89
+ */
90
+ async initialize(configFilePathOrObject) {
91
+ this.config =
92
+ configFilePathOrObject && typeof configFilePathOrObject === 'object'
93
+ ? configFilePathOrObject
94
+ : await (0, config_1.loadAmbitenConfig)(configFilePathOrObject);
95
+ this.initializeLogger();
96
+ await this.initializeRedis();
97
+ await this.initializeMongoProvider();
98
+ this.initializeSchema();
99
+ await this.initializeModel();
100
+ await this.initializeMultiTenancy();
101
+ await this.initializeGraphQL();
102
+ await this.runOnConnectHooks();
103
+ await this.initializeGarbageCollector();
104
+ }
105
+ initializeLogger() {
106
+ const loggerConfig = this.config.logger;
107
+ const defaultTransportConfigs = [
108
+ { type: 'console', options: {} },
109
+ {
110
+ type: 'rotating-file',
111
+ options: {
112
+ filename: './logs/ambiten.log',
113
+ frequency: 'daily',
114
+ compress: false,
115
+ flushInterval: 1000,
116
+ },
117
+ },
118
+ ];
119
+ this.logger = (0, logger_1.setupLogger)({
120
+ ...loggerConfig,
121
+ transports: undefined,
122
+ transportConfigs: loggerConfig?.transportConfigs?.length
123
+ ? loggerConfig.transportConfigs
124
+ : defaultTransportConfigs,
125
+ });
126
+ this.logger.info('Logger initialized', {
127
+ source: 'AmbitenBootstrap',
128
+ });
129
+ }
130
+ async initializeRedis() {
131
+ if (!this.config.features?.useRedisCache || !this.config.features.redisUri) {
132
+ return;
133
+ }
134
+ await redis_manager_1.redis.get(this.config.features.redisUri);
135
+ this.getLogger().info('Redis connected', {
136
+ source: 'AmbitenBootstrap'
137
+ });
138
+ }
139
+ async initializeMongoProvider() {
140
+ const resolvedDbName = this.config.connection?.options?.dbName ||
141
+ this.config.projectName ||
142
+ undefined;
143
+ this.provider =
144
+ this.config.mongoClient ??
145
+ this.config.provider ??
146
+ (0, index_1.createAmbitenClientModule)({
147
+ uri: this.config.connection?.uri || 'mongodb://localhost:27017',
148
+ options: {
149
+ dbName: resolvedDbName,
150
+ ...this.config.connection?.options,
151
+ },
152
+ });
153
+ await this.provider.connect();
154
+ (0, utils_1.configureAmbitenContext)(this.provider);
155
+ if (this.logger) {
156
+ this.getLogger().info('MongoDB connected via AmbitenClientModule', {
157
+ source: 'AmbitenBootstrap'
158
+ });
159
+ }
160
+ else {
161
+ console.log((0, utils_1.colorize)('MongoDB connected via AmbitenClientModule', 'blue'));
162
+ }
163
+ }
164
+ initializeSchema() {
165
+ this.schema = new index_1.Schema(typeof this.config.schema === 'object'
166
+ ? this.config.schema
167
+ : {});
168
+ if (this.config.schema) {
169
+ this.schema.registerSchema(this.config.schema);
170
+ this.getLogger().info('Schema registered', { source: 'AmbitenBootstrap' });
171
+ }
172
+ else {
173
+ this.getLogger().warn('No schema provided, using default schema', { source: 'AmbitenBootstrap' });
174
+ }
175
+ }
176
+ async initializeModel() {
177
+ const collectionName = this.config.model?.collectionName || 'default';
178
+ this.model = (0, utils_1.Model)({
179
+ collectionName,
180
+ schema: this.schema,
181
+ provider: this.provider,
182
+ ctx: this.config.model?.ctx,
183
+ collection: this.config.model?.collection,
184
+ gcConfig: this.config.model?.gcConfig,
185
+ });
186
+ if (this.config.model) {
187
+ await this.model.registerModel({
188
+ ...this.config.model,
189
+ collectionName,
190
+ schema: this.schema,
191
+ provider: this.provider,
192
+ });
193
+ if (this.logger) {
194
+ this.getLogger().info(`Model registered: ${collectionName}`, {
195
+ source: 'AmbitenBootstrap'
196
+ });
197
+ }
198
+ else {
199
+ console.log((0, utils_1.colorize)(`Model registered: ${collectionName}`, 'blue'));
200
+ }
201
+ }
202
+ }
203
+ async initializeMultiTenancy() {
204
+ if (!this.config.multiTenant?.enabled)
205
+ return;
206
+ const tenants = this.config.multiTenant.tenants || {};
207
+ const initOptions = this.config.multiTenant.initOptions || {};
208
+ await (0, tanancy_1.initMultiTenancy)(tenants, initOptions);
209
+ this.getLogger().info('Multi-tenancy initialized', {
210
+ source: 'AmbitenBootstrap',
211
+ tenantCount: Object.keys(tenants).length,
212
+ lazy: initOptions.lazy ?? false,
213
+ });
214
+ }
215
+ async initializeGraphQL() {
216
+ if (!this.config.graphql?.enabled) {
217
+ return;
218
+ }
219
+ this.graphql = new __1.AmbitenGraphQL({
220
+ useRedis: this.config.features?.useRedisCache ?? false,
221
+ customTypeDefs: this.config.features?.typeDefs
222
+ ? Array.isArray(this.config.features.typeDefs)
223
+ ? this.config.features.typeDefs
224
+ : [this.config.features.typeDefs]
225
+ : [],
226
+ customResolvers: this.config.features?.resolvers
227
+ ? Array.isArray(this.config.features.resolvers)
228
+ ? this.config.features.resolvers
229
+ : [this.config.features.resolvers]
230
+ : [],
231
+ provider: this.provider
232
+ });
233
+ await this.graphql.generateSchema();
234
+ if (this.logger) {
235
+ this.getLogger().info('GraphQL schema generated');
236
+ this.getLogger().info('GraphQL initialized');
237
+ }
238
+ else {
239
+ console.log((0, utils_1.colorize)('GraphQL schema generated', 'blue'));
240
+ console.log((0, utils_1.colorize)('GraphQL initialized', 'blue'));
241
+ }
242
+ }
243
+ async runOnConnectHooks() {
244
+ for (const hook of this.onConnectHooks) {
245
+ await hook();
246
+ }
247
+ }
248
+ async initializeGarbageCollector() {
249
+ if (!this.config.advanced?.garbageCollector?.enabled)
250
+ return;
251
+ this.gc = new gc_1.AmbitenGC({
252
+ enabled: this.config.advanced.garbageCollector.enabled ?? true,
253
+ cron: this.config.advanced.gcCron || '0 0 * * *',
254
+ logResults: this.config.advanced.garbageCollector.logResults ?? true,
255
+ continueOnError: true
256
+ });
257
+ console.log('✅ Garbage Collector initialized');
258
+ }
259
+ async registerMultiTenancy(options) {
260
+ const multiTenantConfig = this.config.multiTenant;
261
+ const logger = this.config.logger?.logger;
262
+ if (!multiTenantConfig?.enabled) {
263
+ logger?.warn('Multi-tenancy is not enabled.', {
264
+ source: 'AmbitenBootstrap',
265
+ });
266
+ return;
267
+ }
268
+ const tenants = options?.tenants ?? multiTenantConfig.tenants;
269
+ if (!tenants || Object.keys(tenants).length === 0) {
270
+ logger?.warn('Multi-tenancy is enabled but no tenants were provided.', {
271
+ source: 'AmbitenBootstrap',
272
+ });
273
+ return;
274
+ }
275
+ await (0, tanancy_1.initMultiTenancy)(tenants, {
276
+ lazy: options?.lazy ?? multiTenantConfig.initOptions?.lazy ?? true,
277
+ config: this.config.logger,
278
+ });
279
+ logger?.info('Multi-tenancy registered successfully.', {
280
+ source: 'AmbitenBootstrap',
281
+ tenantCount: Object.keys(tenants).length,
282
+ });
283
+ }
284
+ async cache(key, fetcher, options = {}) {
285
+ if (!redis_manager_1.redis) {
286
+ throw new Error('Redis is not initialized');
287
+ }
288
+ return (0, utils_1.cacheWithRedis)(redis_manager_1.redis, key, fetcher, options);
289
+ }
290
+ async invalidateCache(tenantId, namespace) {
291
+ if (!redis_manager_1.redis) {
292
+ throw new Error('No Redis client available');
293
+ }
294
+ const logger = this.config.logger?.logger;
295
+ if (!tenantId) {
296
+ throw new Error('Tenant ID is required to invalidate cache');
297
+ }
298
+ logger?.info('Invalidating cache for tenant:', {
299
+ source: 'AmbitenBootstrap',
300
+ tenantId,
301
+ namespace: namespace
302
+ });
303
+ await (0, invalidateTenantCache_1.invalidateTenantCache)(redis_manager_1.redis, tenantId, namespace);
304
+ }
305
+ /**
306
+ * Returns the Redis client if Redis is enabled in the configuration.
307
+ */
308
+ async getRedisClient() {
309
+ if (this.config.features?.useRedisCache && this.config.features.redisUri) {
310
+ await redis_manager_1.redis.get(this.config.features.redisUri);
311
+ }
312
+ return redis_manager_1.redis;
313
+ }
314
+ getMongoClient() {
315
+ return this.provider;
316
+ }
317
+ getModel() {
318
+ return this.model;
319
+ }
320
+ getSchema() {
321
+ return this.schema;
322
+ }
323
+ getGraphQL() {
324
+ if (!this.graphql) {
325
+ throw new Error('GraphQL is not initialized.');
326
+ }
327
+ return this.graphql;
328
+ }
329
+ getGCRunner() {
330
+ if (!this.gc) {
331
+ throw new Error('Garbage Collector is not initialized.');
332
+ }
333
+ return this.gc;
334
+ }
335
+ getLogger() {
336
+ return this.logger;
337
+ }
338
+ async shutdown() {
339
+ const logger = this.config.logger?.logger;
340
+ if (redis_manager_1.redis.isOpen) {
341
+ await redis_manager_1.redis.disconnect();
342
+ logger?.info('🧹 Redis connection closed', {
343
+ source: 'AmbitenBootstrap'
344
+ });
345
+ }
346
+ if (this.provider) {
347
+ await this.provider.close();
348
+ logger?.log?.('info', 'MongoDB connection closed');
349
+ }
350
+ logger?.log?.('info', 'Shutdown complete');
351
+ }
352
+ }
353
+ ;
354
+ /**
355
+ * Factory class to create an instance of AmbitenBootstrap.
356
+ * This class encapsulates the logic for initializing the Ambiten application stack,
357
+ * including MongoDB, Multi-Tenancy, Redis, GraphQL logger etc. setup.
358
+ * It can be used to create a fully configured Ambiten instance
359
+ * with optional configuration parameters.
360
+ * @example
361
+ * const Ambiten = await AmbitenBootstrapFactory.create();
362
+ * const db = Ambiten.getMongoClient();
363
+ * await db.connect();
364
+ * const graphql = await Ambiten.getGraphQL();
365
+ * // You can now use the GraphQL instance to generate schema or start a server
366
+ * // or perform other GraphQL related operations
367
+ * graphql.generateSchema();
368
+ * Ambiten.getRedisClient();
369
+ * // or with custom config
370
+ * const Ambiten = await AmbitenBootstrapFactory.create(customConfig);
371
+ * @param {AmbitenConfig} [config] - Optional configuration object for Ambiten.
372
+ * @returns {Promise<AmbitenBootstrap>} - A promise that resolves to an instance of AmbitenBootstrap.
373
+ */
374
+ class AmbitenBootstrapFactory {
375
+ static async create(options = {}) {
376
+ const bootstrap = new AmbitenBootstrap(options.adapter);
377
+ await bootstrap.initialize(options.config);
378
+ return bootstrap;
379
+ }
380
+ }
381
+ exports.AmbitenBootstrapFactory = AmbitenBootstrapFactory;
@@ -0,0 +1,2 @@
1
+ export * from './ambitenBootstrap';
2
+ //# sourceMappingURL=index.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../src/lib-core/bootstrap/index.ts"],"names":[],"mappings":"AAAA,cAAc,oBAAoB,CAAC"}
@@ -0,0 +1,4 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ const tslib_1 = require("tslib");
4
+ tslib_1.__exportStar(require("./ambitenBootstrap"), exports);
@@ -0,0 +1,5 @@
1
+ export * from './ambitenClient';
2
+ export * from './ambitenModelFactory';
3
+ export * from './ambitenSchema';
4
+ export * from './bootstrap';
5
+ //# sourceMappingURL=index.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/lib-core/index.ts"],"names":[],"mappings":"AAAA,cAAc,iBAAiB,CAAC;AAChC,cAAc,uBAAuB,CAAC;AACtC,cAAc,iBAAiB,CAAC;AAChC,cAAc,aAAa,CAAC"}
@@ -0,0 +1,7 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ const tslib_1 = require("tslib");
4
+ tslib_1.__exportStar(require("./ambitenClient"), exports);
5
+ tslib_1.__exportStar(require("./ambitenModelFactory"), exports);
6
+ tslib_1.__exportStar(require("./ambitenSchema"), exports);
7
+ tslib_1.__exportStar(require("./bootstrap"), exports);
@@ -0,0 +1,22 @@
1
+ import { Request, Response, NextFunction } from "express-serve-static-core";
2
+ declare module "express-serve-static-core" {
3
+ interface Request {
4
+ user: {
5
+ _id: string;
6
+ role: string;
7
+ tenantId: string;
8
+ };
9
+ }
10
+ }
11
+ /**
12
+ * Middleware to authorize access to routes based on user roles.
13
+ * This middleware checks if the request contains a valid JWT token,
14
+ * @param roles - An array of roles that are allowed to access the route.
15
+ * @returns
16
+ */
17
+ export declare function authorize(roles: string[]): (req: Request, res: Response, next: NextFunction) => Response | {
18
+ _id: string;
19
+ role: string;
20
+ tenantId: string;
21
+ } | undefined;
22
+ //# sourceMappingURL=auth.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"auth.d.ts","sourceRoot":"","sources":["../../../src/middleware/authorization/auth.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,OAAO,EAAE,QAAQ,EAAE,YAAY,EAAE,MAAM,2BAA2B,CAAC;AAI5E,OAAO,QAAQ,2BAA2B,CAAC;IAC1C,UAAU,OAAO;QAChB,IAAI,EAAE;YAAE,GAAG,EAAE,MAAM,CAAC;YAAC,IAAI,EAAE,MAAM,CAAC;YAAC,QAAQ,EAAE,MAAM,CAAA;SAAE,CAAC;KACtD;CACD;AAED;;;;;GAKG;AACH,wBAAgB,SAAS,CAAC,KAAK,EAAE,MAAM,EAAE,IAChC,KAAK,OAAO,EAAE,KAAK,QAAQ,EAAE,MAAM,YAAY;SAWc,MAAM;UAAQ,MAAM;cAAY,MAAM;cAkB3G"}
@@ -0,0 +1,37 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.authorize = authorize;
4
+ const AuthUtils_1 = require("../../utils/AuthUtils");
5
+ /**
6
+ * Middleware to authorize access to routes based on user roles.
7
+ * This middleware checks if the request contains a valid JWT token,
8
+ * @param roles - An array of roles that are allowed to access the route.
9
+ * @returns
10
+ */
11
+ function authorize(roles) {
12
+ return (req, res, next) => {
13
+ let token;
14
+ const authHeader = req.headers?.authorization || req.headers.Authorization;
15
+ if (typeof authHeader === 'string' && authHeader.startsWith('Bearer ')) {
16
+ token = authHeader.split(' ')[1];
17
+ }
18
+ if (!token) {
19
+ return res.status(401).json({ error: "Access token required" });
20
+ }
21
+ try {
22
+ const decoded = AuthUtils_1.AuthService.verifyToken(token);
23
+ console.info(`Decoded token: ${JSON.stringify(decoded)}`);
24
+ if (!decoded) {
25
+ return res.status(401).json({ error: "Unauthorized" });
26
+ }
27
+ if (!roles.includes(decoded.role)) {
28
+ return res.status(403).json({ error: "Access Denied" });
29
+ }
30
+ return decoded;
31
+ next();
32
+ }
33
+ catch {
34
+ res.status(401).json({ error: "Unauthorized" });
35
+ }
36
+ };
37
+ }
@@ -0,0 +1,4 @@
1
+ export * from './rbac/rbacMiddleware';
2
+ export * from './rbac/rbacTypes';
3
+ export * from './authorization/auth';
4
+ //# sourceMappingURL=index.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/middleware/index.ts"],"names":[],"mappings":"AAAA,cAAc,uBAAuB,CAAC;AACtC,cAAc,kBAAkB,CAAC;AACjC,cAAc,sBAAsB,CAAA"}
@@ -0,0 +1,6 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ const tslib_1 = require("tslib");
4
+ tslib_1.__exportStar(require("./rbac/rbacMiddleware"), exports);
5
+ tslib_1.__exportStar(require("./rbac/rbacTypes"), exports);
6
+ tslib_1.__exportStar(require("./authorization/auth"), exports);
@@ -0,0 +1,103 @@
1
+ import { Role, Permission } from './rbacTypes';
2
+ declare module "express-serve-static-core" {
3
+ interface Request {
4
+ user: {
5
+ _id: string;
6
+ role: string;
7
+ tenantId: string;
8
+ };
9
+ isAdmin: boolean;
10
+ isUser: boolean;
11
+ }
12
+ }
13
+ /**
14
+ * Check if a user has a specific permission
15
+ * @param role The role of the user
16
+ * @param permission The permission to check
17
+ * @returns A promise that resolves to true if the user has the permission, false otherwise
18
+ * @example
19
+ * const hasPermission = await checkPermission('admin', 'createUser');
20
+ * if (hasPermission) {
21
+ * // User has permission to create a user
22
+ * } else {
23
+ * // User does not have permission to create a user
24
+ * }
25
+ */
26
+ export declare function checkPermission(role: Role, permission: Permission): Promise<boolean>;
27
+ /**
28
+ * Get cached data for a specific role and key
29
+ * @param role The role or tenant object
30
+ * @param key The key to retrieve from the cache
31
+ * @return {Promise<any>} A promise that resolves to the cached data or null if not found
32
+ * This function retrieves cached data from Redis based on the provided role and key.
33
+ * It constructs a unique cache key using the role and key, checks if the data exists in the cache,
34
+ * and returns the parsed data if found. If the data is not found, it logs a cache miss and returns null.
35
+ * @throws {Error} If there is an issue with the Redis operation
36
+ * @example
37
+ * // Get cached permissions for role 'admin'
38
+ * const cachedPermissions = await getCachedData('admin', 'permissions');
39
+ * if (cachedPermissions) {
40
+ * console.log('Cached permissions:', cachedPermissions);
41
+ * } else {
42
+ * console.log('No cached permissions found');
43
+ * }
44
+ */
45
+ export declare function getCachedData(role: string | string[] | {
46
+ tenantId: string;
47
+ }, key: string): Promise<any>;
48
+ export declare function setCachedData(role: string | string[] | {
49
+ tenantId: string;
50
+ }, key: string, data: any, ttl: number): Promise<void>;
51
+ /**
52
+ * Invalidate the cache for a specific tenant and role
53
+ * @param tenantId The ID of the tenant
54
+ * @param role The role to invalidate cache for
55
+ * @return {Promise<void>}
56
+ * This function removes the cached permissions for the specified tenant and role.
57
+ * It is useful when permissions change and you want to ensure the cache reflects the latest state.
58
+ * It logs the invalidation action and deletes the cache entry from Redis.
59
+ * This is particularly important in multi-tenant applications where each tenant may have different permissions.
60
+ * @throws {Error} If there is an issue with the Redis operation
61
+ * @example
62
+ * // Invalidate cache for tenant 'tenant123' with role 'admin'
63
+ * await invalidateTenantCache('tenant123', 'admin');
64
+ */
65
+ export declare function invalidateTenantCache(tenantId: string, role: string): Promise<void>;
66
+ /**
67
+ * Middleware to enforce RBAC (Role-Based Access Control) on GraphQL resolvers
68
+ * @param resolver The original resolver function
69
+ * @param permission The required permission for the action
70
+ * @returns A wrapped resolver function that checks permissions
71
+ * @throws {Error} If the user does not have the required permission
72
+ * @example
73
+ * // Wrap a resolver with RBAC enforcement
74
+ * const securedResolver = enforceRBAC(originalResolver, 'createUser');
75
+ *
76
+ * // Use the secured resolver in your GraphQL schema
77
+ * const resolvers = {
78
+ * Mutation: {
79
+ * createUser: securedResolver,
80
+ * }, };
81
+ *
82
+ * In this example, the `enforceRBAC` function wraps the `originalResolver` and checks if the user has the 'createUser' permission before allowing access to the resolver. If the user lacks the required permission, an error is thrown, preventing unauthorized access.
83
+ * * This middleware is essential for implementing fine-grained access control in GraphQL APIs, ensuring that only authorized users can perform specific actions based on their roles and permissions.
84
+ * @remarks This function is designed to be used in GraphQL resolvers to enforce role-based access control (RBAC). It checks if the user has the necessary permissions before allowing access to the resolver function. If the user lacks the required permission, an error is thrown, preventing unauthorized access.
85
+ * * @see {@link checkPermission} for checking user permissions
86
+ * * @see {@link Role} and {@link Permission} for role and permission types
87
+ * * @see {@link rolePermissions} for the mapping of roles to permissions
88
+ * * @see {@link getCachedData} and {@link setCachedData} for caching permissions
89
+ */
90
+ export declare function enforceRBAC(resolver: Function, permission: Permission): (parent: any, args: any, context: any, info: any) => Promise<any>;
91
+ /**
92
+ * Get the RBAC action from a wrapped resolver
93
+ * @param resolver The wrapped resolver function
94
+ * @returns The RBAC action
95
+ */
96
+ export declare function getRBACAction(resolver: Function): any;
97
+ /**
98
+ * Get the original resolver function from a wrapped resolver
99
+ * @param resolver The wrapped resolver function
100
+ * @returns The original resolver function
101
+ */
102
+ export declare function getOriginalResolver(resolver: Function): any;
103
+ //# sourceMappingURL=rbacMiddleware.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"rbacMiddleware.d.ts","sourceRoot":"","sources":["../../../src/middleware/rbac/rbacMiddleware.ts"],"names":[],"mappings":"AACA,OAAO,EAAE,IAAI,EAAE,UAAU,EAAmB,MAAM,aAAa,CAAC;AAmBhE,OAAO,QAAQ,2BAA2B,CAAC;IAC1C,UAAU,OAAO;QAChB,IAAI,EAAE;YAAE,GAAG,EAAE,MAAM,CAAC;YAAC,IAAI,EAAE,MAAM,CAAC;YAAC,QAAQ,EAAE,MAAM,CAAA;SAAE,CAAC;QACtD,OAAO,EAAE,OAAO,CAAC;QACjB,MAAM,EAAE,OAAO,CAAC;KAChB;CACD;AAKD;;;;;;;;;;;;GAYG;AACH,wBAAsB,eAAe,CAAC,IAAI,EAAE,IAAI,EAAE,UAAU,EAAE,UAAU,GAAG,OAAO,CAAC,OAAO,CAAC,CAmC1F;AAGD;;;;;;;;;;;;;;;;;GAiBG;AACH,wBAAsB,aAAa,CAClC,IAAI,EAAE,MAAM,GAAG,MAAM,EAAE,GAAG;IAAE,QAAQ,EAAE,MAAM,CAAA;CAAE,EAC9C,GAAG,EAAE,MAAM,GACT,OAAO,CAAC,GAAG,CAAC,CAed;AAED,wBAAsB,aAAa,CAClC,IAAI,EAAE,MAAM,GAAG,MAAM,EAAE,GAAG;IAAE,QAAQ,EAAE,MAAM,CAAA;CAAE,EAC9C,GAAG,EAAE,MAAM,EACX,IAAI,EAAE,GAAG,EACT,GAAG,EAAE,MAAM,GACT,OAAO,CAAC,IAAI,CAAC,CAgCf;AAED;;;;;;;;;;;;;GAaG;AACH,wBAAsB,qBAAqB,CAAC,QAAQ,EAAE,MAAM,EAAE,IAAI,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC,CAezF;AAED;;;;;;;;;;;;;;;;;;;;;;;GAuBG;AAEH,wBAAgB,WAAW,CAAC,QAAQ,EAAE,QAAQ,EAAE,UAAU,EAAE,UAAU,YACtC,GAAG,QAAQ,GAAG,WAAW,GAAG,QAAQ,GAAG,kBAsBtE;AAGD;;;;GAIG;AAEH,wBAAgB,aAAa,CAAC,QAAQ,EAAE,QAAQ,OAE/C;AAGD;;;;GAIG;AAEH,wBAAgB,mBAAmB,CAAC,QAAQ,EAAE,QAAQ,OAErD"}