@flowerforce/flowerbase 1.0.1-beta.3

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 (292) hide show
  1. package/CHANGELOG.md +0 -0
  2. package/LICENSE +3 -0
  3. package/README.md +18 -0
  4. package/dist/auth/controller.d.ts +8 -0
  5. package/dist/auth/controller.d.ts.map +1 -0
  6. package/dist/auth/controller.js +76 -0
  7. package/dist/auth/dtos.d.ts +6 -0
  8. package/dist/auth/dtos.d.ts.map +1 -0
  9. package/dist/auth/dtos.js +2 -0
  10. package/dist/auth/plugins/jwt.d.ts +14 -0
  11. package/dist/auth/plugins/jwt.d.ts.map +1 -0
  12. package/dist/auth/plugins/jwt.js +68 -0
  13. package/dist/auth/providers/local-userpass/controller.d.ts +8 -0
  14. package/dist/auth/providers/local-userpass/controller.d.ts.map +1 -0
  15. package/dist/auth/providers/local-userpass/controller.js +184 -0
  16. package/dist/auth/providers/local-userpass/dtos.d.ts +35 -0
  17. package/dist/auth/providers/local-userpass/dtos.d.ts.map +1 -0
  18. package/dist/auth/providers/local-userpass/dtos.js +2 -0
  19. package/dist/auth/utils.d.ts +126 -0
  20. package/dist/auth/utils.d.ts.map +1 -0
  21. package/dist/auth/utils.js +122 -0
  22. package/dist/constants.d.ts +18 -0
  23. package/dist/constants.d.ts.map +1 -0
  24. package/dist/constants.js +34 -0
  25. package/dist/features/endpoints/index.d.ts +10 -0
  26. package/dist/features/endpoints/index.d.ts.map +1 -0
  27. package/dist/features/endpoints/index.js +31 -0
  28. package/dist/features/endpoints/interface.d.ts +27 -0
  29. package/dist/features/endpoints/interface.d.ts.map +1 -0
  30. package/dist/features/endpoints/interface.js +2 -0
  31. package/dist/features/endpoints/utils.d.ts +31 -0
  32. package/dist/features/endpoints/utils.d.ts.map +1 -0
  33. package/dist/features/endpoints/utils.js +85 -0
  34. package/dist/features/functions/controller.d.ts +9 -0
  35. package/dist/features/functions/controller.d.ts.map +1 -0
  36. package/dist/features/functions/controller.js +88 -0
  37. package/dist/features/functions/dtos.d.ts +34 -0
  38. package/dist/features/functions/dtos.d.ts.map +1 -0
  39. package/dist/features/functions/dtos.js +2 -0
  40. package/dist/features/functions/index.d.ts +9 -0
  41. package/dist/features/functions/index.d.ts.map +1 -0
  42. package/dist/features/functions/index.js +28 -0
  43. package/dist/features/functions/interface.d.ts +32 -0
  44. package/dist/features/functions/interface.d.ts.map +1 -0
  45. package/dist/features/functions/interface.js +2 -0
  46. package/dist/features/functions/utils.d.ts +23 -0
  47. package/dist/features/functions/utils.d.ts.map +1 -0
  48. package/dist/features/functions/utils.js +75 -0
  49. package/dist/features/rules/index.d.ts +1 -0
  50. package/dist/features/rules/index.d.ts.map +1 -0
  51. package/dist/features/rules/index.js +1 -0
  52. package/dist/features/rules/interface.d.ts +22 -0
  53. package/dist/features/rules/interface.d.ts.map +1 -0
  54. package/dist/features/rules/interface.js +2 -0
  55. package/dist/features/rules/utils.d.ts +3 -0
  56. package/dist/features/rules/utils.d.ts.map +1 -0
  57. package/dist/features/rules/utils.js +31 -0
  58. package/dist/features/triggers/dtos.d.ts +9 -0
  59. package/dist/features/triggers/dtos.d.ts.map +1 -0
  60. package/dist/features/triggers/dtos.js +2 -0
  61. package/dist/features/triggers/index.d.ts +10 -0
  62. package/dist/features/triggers/index.d.ts.map +1 -0
  63. package/dist/features/triggers/index.js +57 -0
  64. package/dist/features/triggers/interface.d.ts +44 -0
  65. package/dist/features/triggers/interface.d.ts.map +1 -0
  66. package/dist/features/triggers/interface.js +2 -0
  67. package/dist/features/triggers/utils.d.ts +16 -0
  68. package/dist/features/triggers/utils.d.ts.map +1 -0
  69. package/dist/features/triggers/utils.js +153 -0
  70. package/dist/index.d.ts +19 -0
  71. package/dist/index.d.ts.map +1 -0
  72. package/dist/index.js +84 -0
  73. package/dist/model.d.ts +2 -0
  74. package/dist/model.d.ts.map +1 -0
  75. package/dist/model.js +2 -0
  76. package/dist/services/api/index.d.ts +36 -0
  77. package/dist/services/api/index.d.ts.map +1 -0
  78. package/dist/services/api/index.js +36 -0
  79. package/dist/services/api/model.d.ts +33 -0
  80. package/dist/services/api/model.d.ts.map +1 -0
  81. package/dist/services/api/model.js +2 -0
  82. package/dist/services/api/utils.d.ts +16 -0
  83. package/dist/services/api/utils.d.ts.map +1 -0
  84. package/dist/services/api/utils.js +45 -0
  85. package/dist/services/aws/index.d.ts +13 -0
  86. package/dist/services/aws/index.d.ts.map +1 -0
  87. package/dist/services/aws/index.js +50 -0
  88. package/dist/services/index.d.ts +41 -0
  89. package/dist/services/index.d.ts.map +1 -0
  90. package/dist/services/index.js +14 -0
  91. package/dist/services/interface.d.ts +3 -0
  92. package/dist/services/interface.d.ts.map +1 -0
  93. package/dist/services/interface.js +2 -0
  94. package/dist/services/mongodb-atlas/index.d.ts +4 -0
  95. package/dist/services/mongodb-atlas/index.d.ts.map +1 -0
  96. package/dist/services/mongodb-atlas/index.js +483 -0
  97. package/dist/services/mongodb-atlas/model.d.ts +39 -0
  98. package/dist/services/mongodb-atlas/model.d.ts.map +1 -0
  99. package/dist/services/mongodb-atlas/model.js +2 -0
  100. package/dist/services/mongodb-atlas/utils.d.ts +8 -0
  101. package/dist/services/mongodb-atlas/utils.d.ts.map +1 -0
  102. package/dist/services/mongodb-atlas/utils.js +33 -0
  103. package/dist/state.d.ts +6 -0
  104. package/dist/state.d.ts.map +1 -0
  105. package/dist/state.js +18 -0
  106. package/dist/utils/context/helpers.d.ts +74 -0
  107. package/dist/utils/context/helpers.d.ts.map +1 -0
  108. package/dist/utils/context/helpers.js +60 -0
  109. package/dist/utils/context/index.d.ts +14 -0
  110. package/dist/utils/context/index.d.ts.map +1 -0
  111. package/dist/utils/context/index.js +50 -0
  112. package/dist/utils/context/interface.d.ts +18 -0
  113. package/dist/utils/context/interface.d.ts.map +1 -0
  114. package/dist/utils/context/interface.js +2 -0
  115. package/dist/utils/crypto/index.d.ts +19 -0
  116. package/dist/utils/crypto/index.d.ts.map +1 -0
  117. package/dist/utils/crypto/index.js +50 -0
  118. package/dist/utils/helpers/someAsync.d.ts +12 -0
  119. package/dist/utils/helpers/someAsync.d.ts.map +1 -0
  120. package/dist/utils/helpers/someAsync.js +56 -0
  121. package/dist/utils/index.d.ts +3 -0
  122. package/dist/utils/index.d.ts.map +1 -0
  123. package/dist/utils/index.js +11 -0
  124. package/dist/utils/initializer/exposeRoutes.d.ts +8 -0
  125. package/dist/utils/initializer/exposeRoutes.d.ts.map +1 -0
  126. package/dist/utils/initializer/exposeRoutes.js +41 -0
  127. package/dist/utils/initializer/registerPlugins.d.ts +19 -0
  128. package/dist/utils/initializer/registerPlugins.d.ts.map +1 -0
  129. package/dist/utils/initializer/registerPlugins.js +84 -0
  130. package/dist/utils/roles/helpers.d.ts +4 -0
  131. package/dist/utils/roles/helpers.d.ts.map +1 -0
  132. package/dist/utils/roles/helpers.js +47 -0
  133. package/dist/utils/roles/interface.d.ts +33 -0
  134. package/dist/utils/roles/interface.d.ts.map +1 -0
  135. package/dist/utils/roles/interface.js +2 -0
  136. package/dist/utils/roles/machines/commonValidators.d.ts +6 -0
  137. package/dist/utils/roles/machines/commonValidators.d.ts.map +1 -0
  138. package/dist/utils/roles/machines/commonValidators.js +34 -0
  139. package/dist/utils/roles/machines/index.d.ts +14 -0
  140. package/dist/utils/roles/machines/index.d.ts.map +1 -0
  141. package/dist/utils/roles/machines/index.js +27 -0
  142. package/dist/utils/roles/machines/interface.d.ts +46 -0
  143. package/dist/utils/roles/machines/interface.d.ts.map +1 -0
  144. package/dist/utils/roles/machines/interface.js +2 -0
  145. package/dist/utils/roles/machines/machine.d.ts +15 -0
  146. package/dist/utils/roles/machines/machine.d.ts.map +1 -0
  147. package/dist/utils/roles/machines/machine.js +97 -0
  148. package/dist/utils/roles/machines/read/A/index.d.ts +3 -0
  149. package/dist/utils/roles/machines/read/A/index.d.ts.map +1 -0
  150. package/dist/utils/roles/machines/read/A/index.js +27 -0
  151. package/dist/utils/roles/machines/read/B/index.d.ts +3 -0
  152. package/dist/utils/roles/machines/read/B/index.d.ts.map +1 -0
  153. package/dist/utils/roles/machines/read/B/index.js +36 -0
  154. package/dist/utils/roles/machines/read/C/index.d.ts +3 -0
  155. package/dist/utils/roles/machines/read/C/index.d.ts.map +1 -0
  156. package/dist/utils/roles/machines/read/C/index.js +38 -0
  157. package/dist/utils/roles/machines/read/D/index.d.ts +3 -0
  158. package/dist/utils/roles/machines/read/D/index.d.ts.map +1 -0
  159. package/dist/utils/roles/machines/read/D/index.js +26 -0
  160. package/dist/utils/roles/machines/read/D/validators.d.ts +4 -0
  161. package/dist/utils/roles/machines/read/D/validators.d.ts.map +1 -0
  162. package/dist/utils/roles/machines/read/D/validators.js +24 -0
  163. package/dist/utils/roles/machines/read/index.d.ts +2 -0
  164. package/dist/utils/roles/machines/read/index.d.ts.map +1 -0
  165. package/dist/utils/roles/machines/read/index.js +8 -0
  166. package/dist/utils/roles/machines/utils.d.ts +37 -0
  167. package/dist/utils/roles/machines/utils.d.ts.map +1 -0
  168. package/dist/utils/roles/machines/utils.js +54 -0
  169. package/dist/utils/roles/machines/write/A/index.d.ts +3 -0
  170. package/dist/utils/roles/machines/write/A/index.d.ts.map +1 -0
  171. package/dist/utils/roles/machines/write/A/index.js +29 -0
  172. package/dist/utils/roles/machines/write/B/index.d.ts +3 -0
  173. package/dist/utils/roles/machines/write/B/index.d.ts.map +1 -0
  174. package/dist/utils/roles/machines/write/B/index.js +47 -0
  175. package/dist/utils/roles/machines/write/C/index.d.ts +3 -0
  176. package/dist/utils/roles/machines/write/C/index.d.ts.map +1 -0
  177. package/dist/utils/roles/machines/write/C/index.js +26 -0
  178. package/dist/utils/roles/machines/write/C/validators.d.ts +4 -0
  179. package/dist/utils/roles/machines/write/C/validators.d.ts.map +1 -0
  180. package/dist/utils/roles/machines/write/C/validators.js +24 -0
  181. package/dist/utils/roles/machines/write/index.d.ts +2 -0
  182. package/dist/utils/roles/machines/write/index.d.ts.map +1 -0
  183. package/dist/utils/roles/machines/write/index.js +7 -0
  184. package/dist/utils/rules-matcher/interface.d.ts +338 -0
  185. package/dist/utils/rules-matcher/interface.d.ts.map +1 -0
  186. package/dist/utils/rules-matcher/interface.js +26 -0
  187. package/dist/utils/rules-matcher/utils.d.ts +11 -0
  188. package/dist/utils/rules-matcher/utils.d.ts.map +1 -0
  189. package/dist/utils/rules-matcher/utils.js +214 -0
  190. package/dist/utils/rules.d.ts +2 -0
  191. package/dist/utils/rules.d.ts.map +1 -0
  192. package/dist/utils/rules.js +22 -0
  193. package/jest.config.ts +24 -0
  194. package/package.json +63 -0
  195. package/project.json +10 -0
  196. package/rollup.config.js +17 -0
  197. package/src/auth/controller.ts +78 -0
  198. package/src/auth/dtos.ts +6 -0
  199. package/src/auth/plugins/jwt.ts +68 -0
  200. package/src/auth/providers/local-userpass/controller.ts +226 -0
  201. package/src/auth/providers/local-userpass/dtos.ts +40 -0
  202. package/src/auth/utils.ts +165 -0
  203. package/src/babel.config.json +3 -0
  204. package/src/constants.ts +22 -0
  205. package/src/fastify.d.ts +28 -0
  206. package/src/features/endpoints/index.ts +27 -0
  207. package/src/features/endpoints/interface.ts +29 -0
  208. package/src/features/endpoints/utils.ts +72 -0
  209. package/src/features/functions/controller.ts +102 -0
  210. package/src/features/functions/dtos.ts +41 -0
  211. package/src/features/functions/index.ts +21 -0
  212. package/src/features/functions/interface.ts +38 -0
  213. package/src/features/functions/utils.ts +82 -0
  214. package/src/features/rules/index.tsx +0 -0
  215. package/src/features/rules/interface.ts +24 -0
  216. package/src/features/rules/utils.ts +20 -0
  217. package/src/features/triggers/dtos.ts +9 -0
  218. package/src/features/triggers/index.ts +34 -0
  219. package/src/features/triggers/interface.ts +44 -0
  220. package/src/features/triggers/utils.ts +157 -0
  221. package/src/global.d.ts +0 -0
  222. package/src/index.ts +75 -0
  223. package/src/model.ts +1 -0
  224. package/src/services/api/index.ts +50 -0
  225. package/src/services/api/model.ts +38 -0
  226. package/src/services/api/utils.ts +39 -0
  227. package/src/services/aws/index.ts +48 -0
  228. package/src/services/index.ts +9 -0
  229. package/src/services/interface.ts +3 -0
  230. package/src/services/mongodb-atlas/index.ts +569 -0
  231. package/src/services/mongodb-atlas/model.ts +67 -0
  232. package/src/services/mongodb-atlas/utils.ts +44 -0
  233. package/src/state.ts +24 -0
  234. package/src/utils/__tests__/STEP_A_STATES.test.ts +54 -0
  235. package/src/utils/__tests__/STEP_B_STATES.test.ts +113 -0
  236. package/src/utils/__tests__/STEP_C_STATES.test.ts +87 -0
  237. package/src/utils/__tests__/STEP_D_STATES.test.ts +93 -0
  238. package/src/utils/__tests__/checkAdditionalFieldsFn.test.ts +45 -0
  239. package/src/utils/__tests__/checkApplyWhen.test.ts +49 -0
  240. package/src/utils/__tests__/checkFieldsPropertyExists.test.ts +47 -0
  241. package/src/utils/__tests__/checkIsValidFieldNameFn.test.ts +190 -0
  242. package/src/utils/__tests__/comparePassword.test.ts +38 -0
  243. package/src/utils/__tests__/evaluateDocumentsFiltersReadFn.test.ts +57 -0
  244. package/src/utils/__tests__/evaluateDocumentsFiltersWriteFn.test.ts +57 -0
  245. package/src/utils/__tests__/evaluateTopLevelReadFn.test.ts +58 -0
  246. package/src/utils/__tests__/evaluateTopLevelWriteFn.test.ts +66 -0
  247. package/src/utils/__tests__/exposeRoutes.test.ts +65 -0
  248. package/src/utils/__tests__/generateContextData.test.ts +75 -0
  249. package/src/utils/__tests__/getDefaultRule.test.ts +29 -0
  250. package/src/utils/__tests__/getKey.test.ts +12 -0
  251. package/src/utils/__tests__/getKeys.test.ts +11 -0
  252. package/src/utils/__tests__/getWinningRole.test.ts +66 -0
  253. package/src/utils/__tests__/hashPassword.test.ts +28 -0
  254. package/src/utils/__tests__/isEmpty.test.ts +17 -0
  255. package/src/utils/__tests__/logMachineInfo.test.ts +15 -0
  256. package/src/utils/__tests__/operators.test.ts +99 -0
  257. package/src/utils/__tests__/readFileContent.test.ts +35 -0
  258. package/src/utils/__tests__/registerPlugins.test.ts +59 -0
  259. package/src/utils/__tests__/rule.test.ts +51 -0
  260. package/src/utils/__tests__/rulesMatcherInterfaces.test.ts +57 -0
  261. package/src/utils/__tests__/rulesMatcherUtils.test.ts +56 -0
  262. package/src/utils/__tests__/someAsync.test.ts +55 -0
  263. package/src/utils/context/helpers.ts +71 -0
  264. package/src/utils/context/index.ts +52 -0
  265. package/src/utils/context/interface.ts +19 -0
  266. package/src/utils/crypto/index.ts +36 -0
  267. package/src/utils/helpers/someAsync.ts +24 -0
  268. package/src/utils/index.ts +5 -0
  269. package/src/utils/initializer/exposeRoutes.ts +26 -0
  270. package/src/utils/initializer/registerPlugins.ts +97 -0
  271. package/src/utils/roles/helpers.ts +47 -0
  272. package/src/utils/roles/interface.ts +42 -0
  273. package/src/utils/roles/machines/commonValidators.ts +24 -0
  274. package/src/utils/roles/machines/index.ts +20 -0
  275. package/src/utils/roles/machines/interface.ts +46 -0
  276. package/src/utils/roles/machines/machine.ts +85 -0
  277. package/src/utils/roles/machines/read/A/index.ts +19 -0
  278. package/src/utils/roles/machines/read/B/index.ts +31 -0
  279. package/src/utils/roles/machines/read/C/index.ts +30 -0
  280. package/src/utils/roles/machines/read/D/index.ts +20 -0
  281. package/src/utils/roles/machines/read/D/validators.ts +24 -0
  282. package/src/utils/roles/machines/read/index.ts +6 -0
  283. package/src/utils/roles/machines/utils.ts +54 -0
  284. package/src/utils/roles/machines/write/A/index.ts +25 -0
  285. package/src/utils/roles/machines/write/B/index.ts +43 -0
  286. package/src/utils/roles/machines/write/C/index.ts +20 -0
  287. package/src/utils/roles/machines/write/C/validators.ts +24 -0
  288. package/src/utils/roles/machines/write/index.ts +5 -0
  289. package/src/utils/rules-matcher/interface.ts +365 -0
  290. package/src/utils/rules-matcher/utils.ts +281 -0
  291. package/src/utils/rules.ts +19 -0
  292. package/tsconfig.json +28 -0
package/CHANGELOG.md ADDED
File without changes
package/LICENSE ADDED
@@ -0,0 +1,3 @@
1
+ MIT License
2
+
3
+ Copyright (c) 2025 FlowerForce
package/README.md ADDED
@@ -0,0 +1,18 @@
1
+ # flowerbase
2
+
3
+ > **A serverless-native MongoDB package designed for modern cloud applications. Lightweight. Fast. Pay-as-you-go.**
4
+
5
+ ---
6
+
7
+ ## ✨ Features
8
+
9
+ - 🚀 **Serverless-ready** — built from the ground up to work in serverless environments like AWS Lambda.
10
+ - 🔄 **MongoDB-compatible API** — drop-in replacement for most common MongoDB queries and models.
11
+ - 🔐 **Secure by default** — Strict access rules.
12
+
13
+ ---
14
+
15
+ ## 📦 Installation
16
+
17
+ ```bash
18
+ npm install flowerbase
@@ -0,0 +1,8 @@
1
+ import { FastifyInstance } from 'fastify';
2
+ /**
3
+ * Controller for handling user authentication, profile retrieval, and session management.
4
+ * @testable
5
+ * @param {FastifyInstance} app - The Fastify instance.
6
+ */
7
+ export declare function authController(app: FastifyInstance): Promise<void>;
8
+ //# sourceMappingURL=controller.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"controller.d.ts","sourceRoot":"","sources":["../../src/auth/controller.ts"],"names":[],"mappings":"AACA,OAAO,EAAE,eAAe,EAAE,MAAM,SAAS,CAAA;AAOzC;;;;GAIG;AACH,wBAAsB,cAAc,CAAC,GAAG,EAAE,eAAe,iBAgExD"}
@@ -0,0 +1,76 @@
1
+ "use strict";
2
+ var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) {
3
+ function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); }
4
+ return new (P || (P = Promise))(function (resolve, reject) {
5
+ function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } }
6
+ function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } }
7
+ function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); }
8
+ step((generator = generator.apply(thisArg, _arguments || [])).next());
9
+ });
10
+ };
11
+ Object.defineProperty(exports, "__esModule", { value: true });
12
+ exports.authController = authController;
13
+ const bson_1 = require("bson");
14
+ const constants_1 = require("../constants");
15
+ const utils_1 = require("./utils");
16
+ const HANDLER_TYPE = 'preHandler';
17
+ /**
18
+ * Controller for handling user authentication, profile retrieval, and session management.
19
+ * @testable
20
+ * @param {FastifyInstance} app - The Fastify instance.
21
+ */
22
+ function authController(app) {
23
+ return __awaiter(this, void 0, void 0, function* () {
24
+ const { authCollection, userCollection } = constants_1.AUTH_CONFIG;
25
+ const db = app.mongo.client.db(constants_1.DB_NAME);
26
+ app.addHook(HANDLER_TYPE, app.jwtAuthentication);
27
+ /**
28
+ * Endpoint to retrieve the authenticated user's profile.
29
+ *
30
+ * @route {GET} /profile
31
+ * @param {import('fastify').FastifyRequest} req - The request object.
32
+ * @returns {Promise<Object>} A promise resolving with the user's profile data.
33
+ */
34
+ app.get(utils_1.AUTH_ENDPOINTS.PROFILE, function (req) {
35
+ return __awaiter(this, void 0, void 0, function* () {
36
+ const user = yield db
37
+ .collection(authCollection)
38
+ .findOne({ _id: bson_1.ObjectId.createFromHexString(req.user.id) });
39
+ return {
40
+ _id: user === null || user === void 0 ? void 0 : user._id.toString(),
41
+ identities: user === null || user === void 0 ? void 0 : user.identities,
42
+ type: 'normal',
43
+ custom_data: user === null || user === void 0 ? void 0 : user.curstom_data,
44
+ data: {
45
+ _id: user === null || user === void 0 ? void 0 : user._id.toString(),
46
+ email: user === null || user === void 0 ? void 0 : user.email
47
+ }
48
+ };
49
+ });
50
+ });
51
+ /**
52
+ * Endpoint to create a new session and generate a new access token.
53
+ *
54
+ * @route {POST} /session
55
+ * @param {import('fastify').FastifyRequest} req - The request object containing the refresh token.
56
+ * @param {import('fastify').FastifyReply} res - The response object.
57
+ * @returns {Promise<SessionCreatedDto>} A promise resolving with the newly created session data.
58
+ */
59
+ app.post(utils_1.AUTH_ENDPOINTS.SESSION, function (req, res) {
60
+ return __awaiter(this, void 0, void 0, function* () {
61
+ if (req.user.typ !== 'refresh') {
62
+ throw new Error(utils_1.AUTH_ERRORS.INVALID_TOKEN);
63
+ }
64
+ const auth_user = yield (db === null || db === void 0 ? void 0 : db.collection(authCollection).findOne({ _id: new this.mongo.ObjectId(req.user.sub) }));
65
+ if (!auth_user) {
66
+ throw new Error(`User with ID ${req.user.sub} not found`);
67
+ }
68
+ const user = yield db.collection(userCollection).findOne({ [constants_1.AUTH_CONFIG.user_id_field]: req.user.sub });
69
+ res.status(201);
70
+ return {
71
+ access_token: this.createAccessToken(Object.assign(Object.assign({}, auth_user), { user_data: user }))
72
+ };
73
+ });
74
+ });
75
+ });
76
+ }
@@ -0,0 +1,6 @@
1
+ export type SessionCreatedDto = {
2
+ access_token: string;
3
+ };
4
+ export type User = unknown;
5
+ export type Arguments<T = unknown> = T[];
6
+ //# sourceMappingURL=dtos.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"dtos.d.ts","sourceRoot":"","sources":["../../src/auth/dtos.ts"],"names":[],"mappings":"AAAA,MAAM,MAAM,iBAAiB,GAAG;IAC9B,YAAY,EAAE,MAAM,CAAA;CACrB,CAAA;AAED,MAAM,MAAM,IAAI,GAAG,OAAO,CAAA;AAC1B,MAAM,MAAM,SAAS,CAAC,CAAC,GAAG,OAAO,IAAI,CAAC,EAAE,CAAA"}
@@ -0,0 +1,2 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
@@ -0,0 +1,14 @@
1
+ type Options = {
2
+ secret: string;
3
+ };
4
+ /**
5
+ * This module is a Fastify plugin that sets up JWT-based authentication and token creation.
6
+ * It registers JWT authentication, and provides methods to create access and refresh tokens.
7
+ * @testable
8
+ * @param {import('fastify').FastifyInstance} fastify - The Fastify instance.
9
+ * @param {Object} opts - Options for the plugin.
10
+ * @param {string} opts.secret - The secret key used for signing JWTs.
11
+ */
12
+ declare const _default: (fastify: import("fastify/fastify").FastifyInstance<import("fastify/fastify").RawServerDefault, import("http").IncomingMessage, import("http").ServerResponse<import("http").IncomingMessage>, import("fastify/fastify").FastifyBaseLogger, import("fastify/fastify").FastifyTypeProviderDefault>, opts: Options) => Promise<void>;
13
+ export default _default;
14
+ //# sourceMappingURL=jwt.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"jwt.d.ts","sourceRoot":"","sources":["../../../src/auth/plugins/jwt.ts"],"names":[],"mappings":"AAIA,KAAK,OAAO,GAAG;IACb,MAAM,EAAE,MAAM,CAAA;CACf,CAAA;AAED;;;;;;;GAOG;iUAC8C,OAAO;AAAxD,wBAmDE"}
@@ -0,0 +1,68 @@
1
+ "use strict";
2
+ var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) {
3
+ function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); }
4
+ return new (P || (P = Promise))(function (resolve, reject) {
5
+ function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } }
6
+ function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } }
7
+ function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); }
8
+ step((generator = generator.apply(thisArg, _arguments || [])).next());
9
+ });
10
+ };
11
+ var __importDefault = (this && this.__importDefault) || function (mod) {
12
+ return (mod && mod.__esModule) ? mod : { "default": mod };
13
+ };
14
+ Object.defineProperty(exports, "__esModule", { value: true });
15
+ const jwt_1 = __importDefault(require("@fastify/jwt"));
16
+ const fastify_plugin_1 = __importDefault(require("fastify-plugin"));
17
+ const mongodb_1 = require("mongodb");
18
+ /**
19
+ * This module is a Fastify plugin that sets up JWT-based authentication and token creation.
20
+ * It registers JWT authentication, and provides methods to create access and refresh tokens.
21
+ * @testable
22
+ * @param {import('fastify').FastifyInstance} fastify - The Fastify instance.
23
+ * @param {Object} opts - Options for the plugin.
24
+ * @param {string} opts.secret - The secret key used for signing JWTs.
25
+ */
26
+ exports.default = (0, fastify_plugin_1.default)(function (fastify, opts) {
27
+ return __awaiter(this, void 0, void 0, function* () {
28
+ const BAAS_ID = new mongodb_1.ObjectId().toString();
29
+ fastify.register(jwt_1.default, {
30
+ secret: opts.secret
31
+ });
32
+ fastify.decorate('jwtAuthentication', function (request, reply) {
33
+ return __awaiter(this, void 0, void 0, function* () {
34
+ try {
35
+ yield request.jwtVerify();
36
+ }
37
+ catch (err) {
38
+ // TODO: handle error
39
+ reply.send(err);
40
+ }
41
+ });
42
+ });
43
+ fastify.decorate('createAccessToken', function (user) {
44
+ const id = user._id.toString();
45
+ const user_data = Object.assign({ _id: id, id }, user.user_data);
46
+ return this.jwt.sign({
47
+ typ: 'access',
48
+ id,
49
+ user_data: user_data,
50
+ custom_data: user_data
51
+ }, {
52
+ iss: BAAS_ID,
53
+ jti: BAAS_ID,
54
+ sub: user._id.toJSON(),
55
+ expiresIn: '300m'
56
+ });
57
+ });
58
+ fastify.decorate('createRefreshToken', function (user) {
59
+ return this.jwt.sign({
60
+ typ: 'refresh',
61
+ baas_id: BAAS_ID
62
+ }, {
63
+ sub: user._id.toJSON(),
64
+ expiresIn: '60d'
65
+ });
66
+ });
67
+ });
68
+ });
@@ -0,0 +1,8 @@
1
+ import { FastifyInstance } from 'fastify';
2
+ /**
3
+ * Controller for handling local user registration and login.
4
+ * @testable
5
+ * @param {FastifyInstance} app - The Fastify instance.
6
+ */
7
+ export declare function localUserPassController(app: FastifyInstance): Promise<void>;
8
+ //# sourceMappingURL=controller.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"controller.d.ts","sourceRoot":"","sources":["../../../../src/auth/providers/local-userpass/controller.ts"],"names":[],"mappings":"AACA,OAAO,EAAE,eAAe,EAAE,MAAM,SAAS,CAAA;AAiBzC;;;;GAIG;AACH,wBAAsB,uBAAuB,CAAC,GAAG,EAAE,eAAe,iBA0MjE"}
@@ -0,0 +1,184 @@
1
+ "use strict";
2
+ var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) {
3
+ function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); }
4
+ return new (P || (P = Promise))(function (resolve, reject) {
5
+ function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } }
6
+ function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } }
7
+ function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); }
8
+ step((generator = generator.apply(thisArg, _arguments || [])).next());
9
+ });
10
+ };
11
+ var __importDefault = (this && this.__importDefault) || function (mod) {
12
+ return (mod && mod.__esModule) ? mod : { "default": mod };
13
+ };
14
+ Object.defineProperty(exports, "__esModule", { value: true });
15
+ exports.localUserPassController = localUserPassController;
16
+ const mail_1 = __importDefault(require("@sendgrid/mail"));
17
+ const constants_1 = require("../../../constants");
18
+ const state_1 = require("../../../state");
19
+ const context_1 = require("../../../utils/context");
20
+ const crypto_1 = require("../../../utils/crypto");
21
+ const utils_1 = require("../../utils");
22
+ /**
23
+ * Controller for handling local user registration and login.
24
+ * @testable
25
+ * @param {FastifyInstance} app - The Fastify instance.
26
+ */
27
+ function localUserPassController(app) {
28
+ return __awaiter(this, void 0, void 0, function* () {
29
+ const { authCollection } = constants_1.AUTH_CONFIG;
30
+ const db = app.mongo.client.db(constants_1.DB_NAME);
31
+ /**
32
+ * Endpoint for user registration.
33
+ *
34
+ * @route {POST} /register
35
+ * @param {RegistrationDto} req - The request object with registration data.
36
+ * @param {FastifyReply} res - The response object.
37
+ * @returns {Promise<Object>} A promise resolving with the newly created user's ID.
38
+ */
39
+ app.post(utils_1.AUTH_ENDPOINTS.REGISTRATION, {
40
+ schema: utils_1.REGISTRATION_SCHEMA
41
+ }, function (req, res) {
42
+ return __awaiter(this, void 0, void 0, function* () {
43
+ const { email, password } = req.body;
44
+ const hashedPassword = yield (0, crypto_1.hashPassword)(password);
45
+ const existingUser = yield db.collection(authCollection).findOne({
46
+ email
47
+ });
48
+ if (existingUser) {
49
+ res.status(409);
50
+ return {
51
+ error: 'This email address is already used'
52
+ };
53
+ }
54
+ const result = yield db.collection(authCollection).insertOne({
55
+ email: email,
56
+ password: hashedPassword,
57
+ custom_data: {
58
+ // todo li faremo arrivare
59
+ }
60
+ });
61
+ yield (db === null || db === void 0 ? void 0 : db.collection(authCollection).updateOne({
62
+ email: email
63
+ }, {
64
+ $set: {
65
+ identities: [
66
+ {
67
+ id: result === null || result === void 0 ? void 0 : result.insertedId.toString(),
68
+ provider_id: result === null || result === void 0 ? void 0 : result.insertedId.toString(),
69
+ provider_type: utils_1.PROVIDER_TYPE,
70
+ provider_data: { email }
71
+ }
72
+ ]
73
+ }
74
+ }));
75
+ res.status(201);
76
+ return {
77
+ userId: result === null || result === void 0 ? void 0 : result.insertedId
78
+ };
79
+ });
80
+ });
81
+ /**
82
+ * Endpoint for user login.
83
+ *
84
+ * @route {POST} /login
85
+ * @param {LoginDto} req - The request object with login data.
86
+ * @returns {Promise<Object>} A promise resolving with access and refresh tokens.
87
+ */
88
+ app.post(utils_1.AUTH_ENDPOINTS.LOGIN, {
89
+ schema: utils_1.LOGIN_SCHEMA
90
+ }, function (req) {
91
+ return __awaiter(this, void 0, void 0, function* () {
92
+ const storedUser = yield db.collection(authCollection).findOne({
93
+ email: req.body.username
94
+ });
95
+ if (!storedUser) {
96
+ throw new Error(utils_1.AUTH_ERRORS.INVALID_CREDENTIALS);
97
+ }
98
+ const passwordMatches = yield (0, crypto_1.comparePassword)(req.body.password, storedUser.password);
99
+ if (!passwordMatches) {
100
+ throw new Error(utils_1.AUTH_ERRORS.INVALID_CREDENTIALS);
101
+ }
102
+ return {
103
+ access_token: this.createAccessToken(storedUser),
104
+ refresh_token: this.createRefreshToken(storedUser),
105
+ device_id: '',
106
+ user_id: storedUser._id.toString()
107
+ };
108
+ });
109
+ });
110
+ /**
111
+ * Endpoint for reset password.
112
+ *
113
+ * @route {POST} /reset/call
114
+ * @param {ResetPasswordDto} req - The request object with th reset request.
115
+ * @returns {Promise<void>}
116
+ */
117
+ app.post(utils_1.AUTH_ENDPOINTS.RESET, {
118
+ schema: utils_1.RESET_SCHEMA
119
+ }, function (req) {
120
+ return __awaiter(this, void 0, void 0, function* () {
121
+ const { resetPasswordCollection, resetPasswordConfig } = constants_1.AUTH_CONFIG;
122
+ const email = req.body.email;
123
+ const storedUser = yield db.collection(authCollection).findOne({
124
+ email
125
+ });
126
+ if (!storedUser) {
127
+ throw new Error(utils_1.AUTH_ERRORS.INVALID_CREDENTIALS);
128
+ }
129
+ const token = (0, crypto_1.generateToken)();
130
+ const tokenId = (0, crypto_1.generateToken)();
131
+ yield (db === null || db === void 0 ? void 0 : db.collection(resetPasswordCollection).updateOne({ email }, { $set: { token, tokenId, email, createdAt: new Date() } }, { upsert: true }));
132
+ if (resetPasswordConfig.runResetFunction && resetPasswordConfig.resetFunctionName) {
133
+ const functionsList = state_1.StateManager.select("functions");
134
+ const services = state_1.StateManager.select("services");
135
+ const currentFunction = functionsList[resetPasswordConfig.resetFunctionName];
136
+ yield (0, context_1.GenerateContext)({
137
+ args: [{ token, tokenId, email }],
138
+ app,
139
+ rules: {},
140
+ user: {},
141
+ currentFunction,
142
+ functionsList,
143
+ services
144
+ });
145
+ return;
146
+ }
147
+ const { from, subject, mailToken, body } = (0, utils_1.getMailConfig)(resetPasswordConfig, token, tokenId);
148
+ mail_1.default.setApiKey(mailToken);
149
+ yield mail_1.default.send({
150
+ to: email,
151
+ from,
152
+ subject,
153
+ html: body
154
+ });
155
+ });
156
+ });
157
+ /**
158
+ * Endpoint for confirm reset password.
159
+ *
160
+ * @route {POST} /reset
161
+ * @param {ConfirmResetPasswordDto} req - The request object with reset data.
162
+ * @returns {Promise<void>}
163
+ */
164
+ app.post(utils_1.AUTH_ENDPOINTS.CONFIRM_RESET, {
165
+ schema: utils_1.CONFIRM_RESET_SCHEMA
166
+ }, function (req) {
167
+ return __awaiter(this, void 0, void 0, function* () {
168
+ const { resetPasswordCollection } = constants_1.AUTH_CONFIG;
169
+ const { token, tokenId, password } = req.body;
170
+ const resetRequest = yield (db === null || db === void 0 ? void 0 : db.collection(resetPasswordCollection).findOne({ token, tokenId }));
171
+ if (!resetRequest) {
172
+ throw new Error(utils_1.AUTH_ERRORS.INVALID_RESET_PARAMS);
173
+ }
174
+ const hashedPassword = yield (0, crypto_1.hashPassword)(password);
175
+ yield db.collection(authCollection).updateOne({ email: resetRequest.email, }, {
176
+ $set: {
177
+ password: hashedPassword
178
+ }
179
+ });
180
+ yield (db === null || db === void 0 ? void 0 : db.collection(resetPasswordCollection).deleteOne({ _id: resetRequest._id }));
181
+ });
182
+ });
183
+ });
184
+ }
@@ -0,0 +1,35 @@
1
+ export type RegisterUserDto = {
2
+ email: string;
3
+ password: string;
4
+ };
5
+ export type LoginUserDto = {
6
+ username: string;
7
+ password: string;
8
+ };
9
+ export type LoginSuccessDto = {
10
+ access_token: string;
11
+ device_id: string;
12
+ refresh_token: string;
13
+ user_id: string;
14
+ };
15
+ export interface RegistrationDto {
16
+ Body: RegisterUserDto;
17
+ }
18
+ export interface LoginDto {
19
+ Body: LoginUserDto;
20
+ Reply: LoginSuccessDto;
21
+ }
22
+ export interface ResetPasswordDto {
23
+ Body: {
24
+ email: string;
25
+ password: string;
26
+ };
27
+ }
28
+ export interface ConfirmResetPasswordDto {
29
+ Body: {
30
+ token: string;
31
+ tokenId: string;
32
+ password: string;
33
+ };
34
+ }
35
+ //# sourceMappingURL=dtos.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"dtos.d.ts","sourceRoot":"","sources":["../../../../src/auth/providers/local-userpass/dtos.ts"],"names":[],"mappings":"AAAA,MAAM,MAAM,eAAe,GAAG;IAC5B,KAAK,EAAE,MAAM,CAAA;IACb,QAAQ,EAAE,MAAM,CAAA;CACjB,CAAA;AAED,MAAM,MAAM,YAAY,GAAG;IACzB,QAAQ,EAAE,MAAM,CAAA;IAChB,QAAQ,EAAE,MAAM,CAAA;CACjB,CAAA;AAED,MAAM,MAAM,eAAe,GAAG;IAC5B,YAAY,EAAE,MAAM,CAAA;IACpB,SAAS,EAAE,MAAM,CAAA;IACjB,aAAa,EAAE,MAAM,CAAA;IACrB,OAAO,EAAE,MAAM,CAAA;CAChB,CAAA;AAED,MAAM,WAAW,eAAe;IAC9B,IAAI,EAAE,eAAe,CAAA;CACtB;AAED,MAAM,WAAW,QAAQ;IACvB,IAAI,EAAE,YAAY,CAAA;IAClB,KAAK,EAAE,eAAe,CAAA;CACvB;AAED,MAAM,WAAW,gBAAgB;IAC/B,IAAI,EAAE;QACJ,KAAK,EAAE,MAAM,CAAA;QACb,QAAQ,EAAE,MAAM,CAAA;KACjB,CAAA;CACF;AAED,MAAM,WAAW,uBAAuB;IACtC,IAAI,EAAE;QACJ,KAAK,EAAE,MAAM,CAAA;QACb,OAAO,EAAE,MAAM,CAAA;QACf,QAAQ,EAAE,MAAM,CAAA;KACjB,CAAA;CACF"}
@@ -0,0 +1,2 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
@@ -0,0 +1,126 @@
1
+ export declare const LOGIN_SCHEMA: {
2
+ body: {
3
+ type: string;
4
+ properties: {
5
+ username: {
6
+ type: string;
7
+ };
8
+ password: {
9
+ type: string;
10
+ };
11
+ };
12
+ required: string[];
13
+ };
14
+ };
15
+ export declare const RESET_SCHEMA: {
16
+ body: {
17
+ type: string;
18
+ properties: {
19
+ email: {
20
+ type: string;
21
+ };
22
+ password: {
23
+ type: string;
24
+ };
25
+ };
26
+ required: string[];
27
+ };
28
+ };
29
+ export declare const CONFIRM_RESET_SCHEMA: {
30
+ body: {
31
+ type: string;
32
+ properties: {
33
+ password: {
34
+ type: string;
35
+ };
36
+ token: {
37
+ type: string;
38
+ };
39
+ tokenId: {
40
+ type: string;
41
+ };
42
+ };
43
+ required: string[];
44
+ };
45
+ };
46
+ export declare const REGISTRATION_SCHEMA: {
47
+ body: {
48
+ type: string;
49
+ properties: {
50
+ email: {
51
+ type: string;
52
+ };
53
+ password: {
54
+ type: string;
55
+ };
56
+ };
57
+ required: string[];
58
+ };
59
+ };
60
+ export declare enum AUTH_ENDPOINTS {
61
+ LOGIN = "/login",
62
+ REGISTRATION = "/register",
63
+ PROFILE = "/profile",
64
+ SESSION = "/session",
65
+ RESET = "/reset/call",
66
+ CONFIRM_RESET = "/reset"
67
+ }
68
+ export declare enum AUTH_ERRORS {
69
+ INVALID_CREDENTIALS = "Invalid credentials",
70
+ INVALID_TOKEN = "Invalid refresh token provided",
71
+ INVALID_RESET_PARAMS = "Invalid token or tokenId provided"
72
+ }
73
+ export interface AuthConfig {
74
+ auth_collection?: string;
75
+ 'api-key': ApiKey;
76
+ 'local-userpass': LocalUserpass;
77
+ }
78
+ interface ApiKey {
79
+ name: string;
80
+ type: string;
81
+ disabled: boolean;
82
+ }
83
+ interface LocalUserpass {
84
+ name: string;
85
+ type: string;
86
+ disabled: boolean;
87
+ config: Config;
88
+ }
89
+ export interface Config {
90
+ autoConfirm: boolean;
91
+ resetFunctionName: string;
92
+ resetPasswordUrl: string;
93
+ runConfirmationFunction: boolean;
94
+ runResetFunction: boolean;
95
+ mailConfig: {
96
+ from: string;
97
+ subject: string;
98
+ mailToken: string;
99
+ };
100
+ }
101
+ export interface CustomUserDataConfig {
102
+ enabled: boolean;
103
+ mongo_service_name: string;
104
+ database_name: string;
105
+ collection_name: string;
106
+ user_id_field: string;
107
+ }
108
+ export declare const PROVIDER_TYPE = "local-userpass";
109
+ /**
110
+ * > Loads the auth config json file
111
+ * @testable
112
+ */
113
+ export declare const loadAuthConfig: () => AuthConfig;
114
+ /**
115
+ * > Loads the custom user data config json file
116
+ * @testable
117
+ */
118
+ export declare const loadCustomUserData: () => CustomUserDataConfig;
119
+ export declare const getMailConfig: (resetPasswordConfig: Config, token: string, tokenId: string) => {
120
+ from: string;
121
+ subject: string;
122
+ mailToken: string;
123
+ body: string;
124
+ };
125
+ export {};
126
+ //# sourceMappingURL=utils.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"utils.d.ts","sourceRoot":"","sources":["../../src/auth/utils.ts"],"names":[],"mappings":"AAEA,eAAO,MAAM,YAAY;;;;;;;;;;;;;CASxB,CAAA;AAED,eAAO,MAAM,YAAY;;;;;;;;;;;;;CASxB,CAAA;AAGD,eAAO,MAAM,oBAAoB;;;;;;;;;;;;;;;;CAUhC,CAAA;AAGD,eAAO,MAAM,mBAAmB;;;;;;;;;;;;;CAS/B,CAAA;AAED,oBAAY,cAAc;IACxB,KAAK,WAAW;IAChB,YAAY,cAAc;IAC1B,OAAO,aAAa;IACpB,OAAO,aAAa;IACpB,KAAK,gBAAgB;IACrB,aAAa,WAAW;CACzB;AAED,oBAAY,WAAW;IACrB,mBAAmB,wBAAwB;IAC3C,aAAa,mCAAmC;IAChD,oBAAoB,sCAAsC;CAC3D;AAED,MAAM,WAAW,UAAU;IACzB,eAAe,CAAC,EAAE,MAAM,CAAA;IACxB,SAAS,EAAE,MAAM,CAAA;IACjB,gBAAgB,EAAE,aAAa,CAAA;CAChC;AAED,UAAU,MAAM;IACd,IAAI,EAAE,MAAM,CAAA;IACZ,IAAI,EAAE,MAAM,CAAA;IACZ,QAAQ,EAAE,OAAO,CAAA;CAClB;AACD,UAAU,aAAa;IACrB,IAAI,EAAE,MAAM,CAAA;IACZ,IAAI,EAAE,MAAM,CAAA;IACZ,QAAQ,EAAE,OAAO,CAAA;IACjB,MAAM,EAAE,MAAM,CAAA;CACf;AAED,MAAM,WAAW,MAAM;IACrB,WAAW,EAAE,OAAO,CAAA;IACpB,iBAAiB,EAAE,MAAM,CAAA;IACzB,gBAAgB,EAAE,MAAM,CAAA;IACxB,uBAAuB,EAAE,OAAO,CAAA;IAChC,gBAAgB,EAAE,OAAO,CAAA;IACzB,UAAU,EAAE;QACV,IAAI,EAAE,MAAM,CAAA;QACZ,OAAO,EAAE,MAAM,CAAA;QACf,SAAS,EAAE,MAAM,CAAA;KAClB,CAAA;CACF;AAED,MAAM,WAAW,oBAAoB;IACnC,OAAO,EAAE,OAAO,CAAA;IAChB,kBAAkB,EAAE,MAAM,CAAA;IAC1B,aAAa,EAAE,MAAM,CAAA;IACrB,eAAe,EAAE,MAAM,CAAA;IACvB,aAAa,EAAE,MAAM,CAAA;CACtB;AAED,eAAO,MAAM,aAAa,mBAAmB,CAAA;AAE7C;;;GAGG;AACH,eAAO,MAAM,cAAc,QAAO,UAEjC,CAAA;AAED;;;GAGG;AACH,eAAO,MAAM,kBAAkB,QAAO,oBAErC,CAAA;AAID,eAAO,MAAM,aAAa,GAAI,qBAAqB,MAAM,EAAE,OAAO,MAAM,EAAE,SAAS,MAAM;;;;;CAyCxF,CAAA"}