@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
@@ -0,0 +1,66 @@
1
+
2
+ import { Document, ObjectId, WithId } from "mongodb"
3
+ import { User } from '../../auth/dtos';
4
+ import { Role } from "../roles/interface";
5
+ import * as Utils from "../roles/machines/utils";
6
+
7
+ const { getWinningRole } = Utils
8
+
9
+ const mockUser = {
10
+ id: 'user123',
11
+ role: 'admin',
12
+ name: 'Test User',
13
+ } as User;
14
+
15
+ const mockDocument = {
16
+ _id: new ObjectId(),
17
+ field: 'value',
18
+ } as WithId<Document>;
19
+
20
+ const mockRoles = [
21
+ { name: 'Editor', apply_when: { condition: 'test' } },
22
+ { name: 'Viewer', apply_when: { condition: 'other' } }
23
+ ] as Role[]
24
+
25
+
26
+ describe('getWinningRole', () => {
27
+ beforeEach(() => {
28
+ jest.clearAllMocks();
29
+ });
30
+
31
+ it('should return null if roles array is empty', () => {
32
+ expect(getWinningRole(mockDocument, mockUser, [])).toBeNull();
33
+ expect(getWinningRole(mockDocument, mockUser, undefined)).toBeNull();
34
+ });
35
+
36
+ it('should return the first matching role', () => {
37
+ const mockCheckApplyWhen = jest.spyOn(Utils, "checkApplyWhen").mockReturnValueOnce(true)
38
+ const result = getWinningRole(mockDocument, mockUser, mockRoles);
39
+ expect(result).toEqual(mockRoles[0]);
40
+ expect(mockCheckApplyWhen).toHaveBeenCalledWith(mockRoles[0].apply_when, mockUser, mockDocument);
41
+ expect(mockCheckApplyWhen).toHaveBeenCalledTimes(1);
42
+ mockCheckApplyWhen.mockReset()
43
+ });
44
+
45
+ it('should return null if no roles match', () => {
46
+ const mockCheckApplyWhen = jest.spyOn(Utils, "checkApplyWhen").mockReturnValue(false)
47
+ const result = getWinningRole(mockDocument, mockUser, mockRoles);
48
+ expect(result).toBeNull();
49
+ expect(mockCheckApplyWhen).toHaveBeenCalledTimes(mockRoles.length);
50
+ mockCheckApplyWhen.mockReset()
51
+ });
52
+
53
+ it('should check all roles until it finds a match', () => {
54
+ const mockCheckApplyWhen = jest.spyOn(Utils, "checkApplyWhen").mockReturnValueOnce(false).mockReturnValueOnce(true)
55
+ const result = getWinningRole(mockDocument, mockUser, mockRoles);
56
+ expect(result).toEqual(mockRoles[1]);
57
+ expect(mockCheckApplyWhen).toHaveBeenCalledTimes(2);
58
+ mockCheckApplyWhen.mockReset()
59
+ });
60
+
61
+ it('should handle null document correctly', () => {
62
+ jest.spyOn(Utils, "checkApplyWhen").mockReturnValue(true)
63
+ const result = getWinningRole(null, mockUser, mockRoles);
64
+ expect(result).toEqual(mockRoles[0]);
65
+ });
66
+ });
@@ -0,0 +1,28 @@
1
+ import { hashPassword } from '../crypto';
2
+
3
+ describe('hashPassword', () => {
4
+ beforeEach(() => {
5
+ jest.clearAllMocks();
6
+ });
7
+
8
+ it('should return a hashed password with a valid format', async () => {
9
+ const plaintext = 'mySecretPassword';
10
+ const hashedPassword = await hashPassword(plaintext);
11
+ expect(hashedPassword).toMatch(/^[a-f0-9]+\.[a-f0-9]+$/);
12
+ const [storedHash, salt] = hashedPassword.split('.');
13
+ expect(storedHash).toBeDefined();
14
+ expect(salt).toBeDefined();
15
+ });
16
+ it('should generate different hashes for different passwords', async () => {
17
+ const hash1 = await hashPassword('password1');
18
+ const hash2 = await hashPassword('password2');
19
+ expect(hash1).not.toBe(hash2);
20
+ });
21
+ it('should generate different hashes for the same password (due to different salts)', async () => {
22
+ const plaintext = 'samePassword';
23
+ const hash1 = await hashPassword(plaintext);
24
+ const hash2 = await hashPassword(plaintext);
25
+ expect(hash1).not.toBe(hash2);
26
+ });
27
+
28
+ });
@@ -0,0 +1,17 @@
1
+ import rulesMatcherUtils from "../rules-matcher/utils";
2
+
3
+ describe('isEmpty', () => {
4
+
5
+ it('should check if a value is Empty', () => {
6
+ expect(rulesMatcherUtils.isEmpty(undefined)).toBe(true)
7
+ expect(rulesMatcherUtils.isEmpty(null)).toBe(true)
8
+ expect(rulesMatcherUtils.isEmpty(() => { })).toBe(false)
9
+ expect(rulesMatcherUtils.isEmpty("")).toBe(true)
10
+ expect(rulesMatcherUtils.isEmpty("test")).toBe(false)
11
+ expect(rulesMatcherUtils.isEmpty(["test"])).toBe(false)
12
+ expect(rulesMatcherUtils.isEmpty([])).toBe(true)
13
+ expect(rulesMatcherUtils.isEmpty({})).toBe(true)
14
+ expect(rulesMatcherUtils.isEmpty({ some: "test" })).toBe(false)
15
+ expect(rulesMatcherUtils.isEmpty(new Date())).toBe(false)
16
+ });
17
+ });
@@ -0,0 +1,15 @@
1
+ import { logMachineInfo } from "../roles/machines/utils";
2
+
3
+ describe('logMachineInfo', () => {
4
+ beforeEach(() => {
5
+ jest.clearAllMocks();
6
+ });
7
+
8
+ it('should log all the info only if enabled', () => {
9
+ const log = jest.spyOn(console, "log").mockImplementation()
10
+ logMachineInfo({ enabled: true, machine: "A", step: 1, stepName: "test" })
11
+ logMachineInfo({ enabled: false, machine: "A", step: 1, stepName: "test" })
12
+ expect(log).toHaveBeenNthCalledWith(1, "MACHINE A -> STEP 1: test")
13
+ log.mockRestore()
14
+ });
15
+ });
@@ -0,0 +1,99 @@
1
+ import { operators } from "../rules-matcher/utils";
2
+
3
+ describe('operators', () => {
4
+ beforeEach(() => {
5
+ jest.clearAllMocks();
6
+ });
7
+
8
+ it("should check equals values", () => {
9
+ expect(operators.$eq("a", "a")).toBe(true)
10
+ expect(!operators.$eq("a", "b")).toBe(true)
11
+ })
12
+ it("should check different values", () => {
13
+ expect(operators.$ne("a", "a")).toBe(false)
14
+ expect(operators.$ne("a", "b")).toBe(true)
15
+ })
16
+ it("should check string length values", () => {
17
+ // test $strGt
18
+ expect(operators.$strGt("test", 2)).toBe(true)
19
+ expect(operators.$strGt("test", 15)).toBe(false)
20
+ expect(operators.$strGt("test", 4)).toBe(false)
21
+ // test $strGte
22
+ expect(operators.$strGte("test", 2)).toBe(true)
23
+ expect(operators.$strGte("test", 15)).toBe(false)
24
+ expect(operators.$strGte("test", 4)).toBe(true)
25
+ // test $strLt
26
+ expect(operators.$strLt("test", 2)).toBe(false)
27
+ expect(operators.$strLt("test", 15)).toBe(true)
28
+ expect(operators.$strLt("test", 4)).toBe(false)
29
+ // test $strLte
30
+ expect(operators.$strLte("test", 2)).toBe(false)
31
+ expect(operators.$strLte("test", 15)).toBe(true)
32
+ expect(operators.$strLte("test", 4)).toBe(true)
33
+ })
34
+ it("should check if a value exists", () => {
35
+ expect(operators.$exists({ name: 1 }, true)).toBe(true)
36
+ expect(operators.$exists({}, false)).toBe(true)
37
+ expect(operators.$exists({}, true)).toBe(false)
38
+ expect(operators.$exists(undefined, false)).toBe(true)
39
+ expect(operators.$exists(null, true)).toBe(false)
40
+ expect(operators.$exists("", true)).toBe(false)
41
+ expect(operators.$exists("test", true)).toBe(true)
42
+ expect(operators.$exists(0, true)).toBe(true)
43
+ expect(operators.$exists([], true)).toBe(false)
44
+ expect(operators.$exists([1], true)).toBe(true)
45
+ expect(operators.$exists(new Date(), true)).toBe(true)
46
+ expect(operators.$exists(() => { }, true)).toBe(true)
47
+ })
48
+ it("should compare numbers", () => {
49
+ // test $gt
50
+ expect(operators.$gt(2, 3)).toBe(false)
51
+ expect(operators.$gt(2, 2)).toBe(false)
52
+ expect(operators.$gt(3, 2)).toBe(true)
53
+ // test $gte
54
+ expect(operators.$gte(2, 3)).toBe(false)
55
+ expect(operators.$gte(2, 2)).toBe(true)
56
+ expect(operators.$gte(3, 2)).toBe(true)
57
+ // test $lt
58
+ expect(operators.$lt(2, 3)).toBe(true)
59
+ expect(operators.$lt(2, 2)).toBe(false)
60
+ expect(operators.$lt(3, 2)).toBe(false)
61
+ // test $lte
62
+ expect(operators.$lte(2, 3)).toBe(true)
63
+ expect(operators.$lte(2, 2)).toBe(true)
64
+ expect(operators.$lte(3, 2)).toBe(false)
65
+ }
66
+ )
67
+ it("should find a value in an array", () => {
68
+ expect(operators.$in(2, [3])).toBe(false)
69
+ expect(operators.$in(3, [3, 4, 5])).toBe(true)
70
+ expect(operators.$in([3, 4], [3, 4, 5])).toBe(true)
71
+ expect(operators.$in([3, 6], [3, 4, 5])).toBe(true)
72
+ expect(operators.$in({ name: "ciao" }, [{ name: "ciao" }, 4, 5])).toBe(false)
73
+ })
74
+ it("should check if a value isn't in an array", () => {
75
+ expect(operators.$nin(2, [3])).toBe(true)
76
+ expect(operators.$nin(3, [3, 4, 5])).toBe(false)
77
+ expect(operators.$nin([3, 4], [3, 4, 5])).toBe(false)
78
+ expect(operators.$nin([3, 6], [3, 4, 5])).toBe(false)
79
+ expect(operators.$nin({ name: "ciao" }, [{ name: "ciao" }, 4, 5])).toBe(true)
80
+ })
81
+ it("should find all values in an array", () => {
82
+ expect(operators.$all(2, [3])).toBe(false)
83
+ expect(operators.$all(3, [3, 4, 5])).toBe(false)
84
+ expect(operators.$all([3], [3, 4, 5])).toBe(false)
85
+ expect(operators.$all([3, 4, 5], [3, 4, 5])).toBe(true)
86
+ expect(operators.$all([3, 6], [3, 4, 5])).toBe(false)
87
+ expect(operators.$all({ name: "ciao" }, [{ name: "ciao" }, 4, 5])).toBe(false)
88
+ expect(operators.$all([{ name: "ciao" }, 4, 5], [{ name: "ciao" }, 4, 5])).toBe(false)
89
+ })
90
+ it("should check regex", () => {
91
+ const emailRegex = /^[a-zA-Z0-9._%+-]+@[a-zA-Z0-9.-]+\.[a-zA-Z]{2,}$/
92
+ expect(operators.$regex("test@gmail.com", emailRegex)).toBe(true)
93
+ expect(operators.$regex("test.com", emailRegex)).toBe(false)
94
+ const numberRegex = /^\d+$/
95
+ expect(operators.$regex("1234567890", numberRegex)).toBe(true)
96
+ expect(operators.$regex("12345r", numberRegex)).toBe(false)
97
+
98
+ })
99
+ });
@@ -0,0 +1,35 @@
1
+ import fs from 'fs';
2
+ import { readFileContent, readJsonContent } from '..';
3
+
4
+ jest.mock('fs');
5
+
6
+ describe('File Reading Functions', () => {
7
+ const mockFilePath = '/mock/path/file.txt';
8
+ const mockJsonPath = '/mock/path/data.json';
9
+
10
+ beforeEach(() => {
11
+ jest.clearAllMocks();
12
+ });
13
+
14
+ it('should read file content correctly', () => {
15
+ const mockContent = 'Hello, world!';
16
+ (fs.readFileSync as jest.Mock).mockReturnValue(mockContent);
17
+ const result = readFileContent(mockFilePath);
18
+ expect(fs.readFileSync).toHaveBeenCalledWith(mockFilePath, 'utf-8');
19
+ expect(result).toBe(mockContent);
20
+ });
21
+
22
+ it('should read JSON content correctly', () => {
23
+ const mockJsonContent = '{"name": "Alice", "age": 30}';
24
+ (fs.readFileSync as jest.Mock).mockReturnValue(mockJsonContent);
25
+ const result = readJsonContent(mockJsonPath);
26
+ expect(fs.readFileSync).toHaveBeenCalledWith(mockJsonPath, 'utf-8');
27
+ expect(result).toEqual(JSON.parse(mockJsonContent));
28
+ });
29
+
30
+ it('should throw an error when JSON is invalid', () => {
31
+ const invalidJson = '{name: Alice, age: 30}';
32
+ (fs.readFileSync as jest.Mock).mockReturnValue(invalidJson);
33
+ expect(() => readJsonContent(mockJsonPath)).toThrow(SyntaxError);
34
+ });
35
+ });
@@ -0,0 +1,59 @@
1
+ import cors from '@fastify/cors'
2
+ import fastifyMongodb from '@fastify/mongodb'
3
+ import { authController } from '../../auth/controller'
4
+ import jwtAuthPlugin from '../../auth/plugins/jwt'
5
+ import { localUserPassController } from '../../auth/providers/local-userpass/controller'
6
+ import { Functions } from '../../features/functions/interface'
7
+ import { registerPlugins } from '../initializer/registerPlugins'
8
+
9
+ const MOCKED_API_VERSION = '/api/client/v2'
10
+
11
+ jest.mock('../../constants', () => ({
12
+ API_VERSION: '/api/client/v2'
13
+ }))
14
+
15
+ const mockDbUrl = 'mongodb://localhost:27017/testdb'
16
+ const mockSecret = 'test-secret'
17
+
18
+ const errorMock = jest.fn().mockImplementation(() => {
19
+ throw new Error('Plugin registration failed')
20
+ })
21
+ const registerMock = jest.fn()
22
+
23
+ describe('registerPlugins', () => {
24
+ beforeEach(() => {
25
+ jest.clearAllMocks();
26
+ });
27
+
28
+ it('should register all plugins successfully', async () => {
29
+ await registerPlugins({
30
+ register: registerMock,
31
+ mongodbUrl: mockDbUrl,
32
+ jwtSecret: mockSecret,
33
+ functionsList: {} as Functions
34
+ })
35
+
36
+ // Check Plugins Registration
37
+ expect(registerMock).toHaveBeenCalledTimes(5)
38
+ expect(registerMock).toHaveBeenCalledWith(cors, { origin: '*', methods: ['POST', 'GET'] })
39
+ expect(registerMock).toHaveBeenCalledWith(fastifyMongodb, { forceClose: true, url: mockDbUrl })
40
+ expect(registerMock).toHaveBeenCalledWith(jwtAuthPlugin, { secret: mockSecret })
41
+ expect(registerMock).toHaveBeenCalledWith(authController, { prefix: `${MOCKED_API_VERSION}/auth` })
42
+ expect(registerMock).toHaveBeenCalledWith(localUserPassController, { prefix: `${MOCKED_API_VERSION}/app/:appId/auth/providers/local-userpass` })
43
+ })
44
+
45
+ it('should handle errors in the catch block', async () => {
46
+
47
+ const errorLog = jest.spyOn(console, 'error').mockImplementation(() => { })
48
+
49
+ await registerPlugins({
50
+ register: errorMock,
51
+ mongodbUrl: mockDbUrl,
52
+ jwtSecret: mockSecret,
53
+ functionsList: {} as Functions
54
+ })
55
+
56
+ expect(errorLog).toHaveBeenCalledWith('Error while registering plugins', 'Plugin registration failed')
57
+ errorLog.mockRestore()
58
+ })
59
+ })
@@ -0,0 +1,51 @@
1
+ import rulesMatcherUtils from '../rules-matcher/utils';
2
+
3
+
4
+ describe('rule function', () => {
5
+ it('should return valid true if the operator and value match', () => {
6
+ const mockData = {
7
+ user: { name: 'John', age: 25 }
8
+ };
9
+ const mockOptions = { prefix: 'user' };
10
+ const mockValueBlock = { name: { $eq: 'John' } };
11
+ const result = rulesMatcherUtils.rule(mockValueBlock, mockData, mockOptions);
12
+ expect(result.valid).toBe(true);
13
+ expect(result.name).toBe('user.name___$eq');
14
+ });
15
+
16
+ it('should return valid false if the operator and value do not match', () => {
17
+ const mockData = {
18
+ user: { name: 'John', age: 25 }
19
+ };
20
+ const mockOptions = { prefix: 'user' };
21
+ const mockValueBlock = { name: { $eq: 'Doe' } };
22
+ const result = rulesMatcherUtils.rule(mockValueBlock, mockData, mockOptions);
23
+
24
+ expect(result.valid).toBe(false);
25
+ expect(result.name).toBe('user.name___$eq');
26
+ });
27
+
28
+ it('should handle $ref: values correctly', () => {
29
+ const mockData = {
30
+ user: { name: 'John', age: 25 }
31
+ };
32
+ const mockOptions = { prefix: 'user' };
33
+ const mockValueBlock = { name: { $eq: '$ref:user.refName' } };
34
+ const result = rulesMatcherUtils.rule(mockValueBlock, mockData, mockOptions);
35
+
36
+ expect(result.valid).toBe(false);
37
+ expect(result.name).toBe('user.name___$eq');
38
+ });
39
+
40
+ it('should throw an error if the operator is missing', () => {
41
+
42
+ const mockData = {
43
+ user: { name: 'John', age: 25 }
44
+ };
45
+ const mockOptions = { prefix: 'user' };
46
+ const missingOperatorBlock = { name: { $notFoundOperator: 'value' } };
47
+ expect(() => {
48
+ rulesMatcherUtils.rule(missingOperatorBlock, mockData, mockOptions);
49
+ }).toThrow('Error missing operator:$notFoundOperator');
50
+ });
51
+ });
@@ -0,0 +1,57 @@
1
+ import { RulesModes, RulesOperators, RulesOperatorsInArray, RulesValuesType } from '../rules-matcher/interface';
2
+
3
+ describe('Enums and Types', () => {
4
+ it('should have correct values in RulesOperators enum', () => {
5
+ expect(RulesOperators.$exists).toBe('$exists');
6
+ expect(RulesOperators.$eq).toBe('$eq');
7
+ expect(RulesOperators.$ne).toBe('$ne');
8
+ expect(RulesOperators.$gt).toBe('$gt');
9
+ expect(RulesOperators.$gte).toBe('$gte');
10
+ expect(RulesOperators.$lt).toBe('$lt');
11
+ expect(RulesOperators.$lte).toBe('$lte');
12
+ expect(RulesOperators.$strGt).toBe('$strGt');
13
+ expect(RulesOperators.$strGte).toBe('$strGte');
14
+ expect(RulesOperators.$strLt).toBe('$strLt');
15
+ expect(RulesOperators.$strLte).toBe('$strLte');
16
+ expect(RulesOperators.$in).toBe('$in');
17
+ expect(RulesOperators.$nin).toBe('$nin');
18
+ expect(RulesOperators.$all).toBe('$all');
19
+ expect(RulesOperators.$regex).toBe('$regex');
20
+ });
21
+
22
+ it('should validate RulesOperatorsInArray type', () => {
23
+ const valid: RulesOperatorsInArray<{ age: number }> = {
24
+ age: {
25
+ $gt: 25
26
+ }
27
+ };
28
+ expect(valid).toHaveProperty('age');
29
+ expect(valid.age).toHaveProperty('$gt', 25);
30
+ const partial: RulesOperatorsInArray<{ name: string }> = {
31
+ name: {
32
+ $eq: 'John Doe'
33
+ }
34
+ };
35
+ expect(partial).toHaveProperty('name');
36
+ expect(partial.name).toHaveProperty('$eq', 'John Doe');
37
+ });
38
+
39
+ it('should validate RulesValuesType type', () => {
40
+ const valid: RulesValuesType<{ age: number }> = {
41
+ "$form.isValid": true,
42
+ age: 30
43
+ };
44
+ expect(valid["$form.isValid"]).toBe(true);
45
+ expect(valid.age).toBe(30);
46
+ const withoutFormValid: RulesValuesType<{ age: number }> = {
47
+ age: 25
48
+ };
49
+ expect(withoutFormValid["$form.isValid"]).toBeUndefined();
50
+ expect(withoutFormValid.age).toBe(25);
51
+ });
52
+
53
+ it('should validate RulesModes enum values', () => {
54
+ expect(RulesModes.$and).toBe('$and');
55
+ expect(RulesModes.$or).toBe('$or');
56
+ });
57
+ });
@@ -0,0 +1,56 @@
1
+ import rulesMatcherUtils from "../rules-matcher/utils";
2
+ const { forceArray, isNumber, isFunction, isString, isDate, isObject, getPath, forceNumber, getDefaultStringValue, getTypeOf } = rulesMatcherUtils
3
+
4
+ describe('rulesMatcherUtils', () => {
5
+ beforeEach(() => {
6
+ jest.clearAllMocks();
7
+ });
8
+
9
+ it('should check all utils', () => {
10
+ // isNumber
11
+ expect(isNumber(2)).toBe(true)
12
+ expect(isNumber("33")).toBe(true)
13
+ expect(isNumber("ciao")).toBe(false)
14
+ expect(isNumber("ciao12")).toBe(false)
15
+ // isFunction
16
+ expect(isFunction(2)).toBe(false)
17
+ expect(isFunction("ciao")).toBe(false)
18
+ expect(isFunction(() => { })).toBe(true)
19
+ expect(isFunction(function test() { })).toBe(true)
20
+ // isString
21
+ expect(isString(2)).toBe(false)
22
+ expect(isString("2")).toBe(true)
23
+ expect(isString("ciao")).toBe(true)
24
+ // isDate
25
+ expect(isDate(2)).toBe(false)
26
+ expect(isDate(new Date())).toBe(true)
27
+ expect(isDate({})).toBe(false)
28
+ // isObject
29
+ expect(isObject({})).toBe(true)
30
+ expect(isObject("test")).toBe(false)
31
+ expect(isObject([])).toBe(true)
32
+ // forceNumber
33
+ expect(forceNumber([1, 2, 3])).toBe(3)
34
+ expect(forceNumber("2")).toBe(2)
35
+ expect(forceNumber("test")).toBe(0)
36
+ // getDefaultStringValue
37
+ expect(getDefaultStringValue("$required")).toEqual({ op: '$exists', value: true })
38
+ expect(getDefaultStringValue("$exists")).toEqual({ op: '$exists', value: true })
39
+ expect(getDefaultStringValue("test")).toEqual({ op: '$eq', value: "test" })
40
+ // getTypeOf
41
+ expect(getTypeOf([])).toBe("array")
42
+ expect(getTypeOf(2)).toBe("number")
43
+ expect(getTypeOf(null)).toBe(null)
44
+ expect(getTypeOf("test")).toBe(typeof "test")
45
+ expect(getTypeOf(undefined)).toBe(typeof undefined)
46
+ // forceArray
47
+ expect(forceArray(["test"])).toEqual(["test"])
48
+ expect(forceArray(2)).toEqual([2])
49
+ expect(forceArray({ test: "test" })).toEqual([{ test: "test" }])
50
+ // getPath
51
+ expect(getPath("data.name", "user")).toBe("user.data.name")
52
+ expect(getPath("data.name")).toBe("data.name")
53
+ expect(getPath("^data.name")).toBe("data.name")
54
+ expect(getPath("$data.name")).toBe("$data.name")
55
+ });
56
+ });
@@ -0,0 +1,55 @@
1
+ import { someAsync } from "../helpers/someAsync";
2
+
3
+ const mockArray = [1, 3, 4, 4, 5]
4
+
5
+ describe('someAsync function', () => {
6
+ beforeEach(() => {
7
+ jest.clearAllMocks();
8
+ });
9
+ it('should return true', async () => {
10
+ let i = 0
11
+ const callback = async (el: unknown, index: number): Promise<boolean> => {
12
+ i = index
13
+ return new Promise(resolve => {
14
+ setTimeout(() => {
15
+ resolve(index < 6);
16
+ }, 0);
17
+ });
18
+ }
19
+ const response = await someAsync(mockArray, callback)
20
+ expect(response).toEqual(true)
21
+ expect(i).toEqual(0)
22
+ });
23
+ it('should return true for the last element', async () => {
24
+ let i = 0
25
+ const callback = async (el: unknown, index: number): Promise<boolean> => {
26
+ i = index
27
+ return new Promise(resolve => {
28
+ setTimeout(() => {
29
+ resolve(index > 3);
30
+ }, 0);
31
+ });
32
+ }
33
+ const response = await someAsync(mockArray, callback)
34
+ expect(response).toEqual(true)
35
+ expect(i).toEqual(4)
36
+ });
37
+
38
+ it('should return false', async () => {
39
+ let i = 0
40
+ const callback = async (el: unknown, index: number): Promise<boolean> => {
41
+ i = index
42
+ return new Promise(resolve => {
43
+ setTimeout(() => {
44
+ resolve(index > 4);
45
+ }, 0);
46
+ });
47
+ }
48
+ const response = await someAsync(mockArray, callback)
49
+ expect(response).toEqual(false)
50
+ expect(i).toEqual(4)
51
+ });
52
+
53
+
54
+
55
+ })
@@ -0,0 +1,71 @@
1
+ import { mongodb } from '@fastify/mongodb'
2
+ import { Arguments } from '../../auth/dtos'
3
+ import { Function } from '../../features/functions/interface'
4
+ import { GenerateContextDataParams } from './interface'
5
+
6
+ /**
7
+ * > Used to generate the current context data
8
+ * @testable
9
+ * @param user -> the current user
10
+ * @param services -> the list of all services
11
+ * @param app -> the fastify instance
12
+ * @param rules -> the rules object
13
+ * @param currentFunction -> the function's name that should be called
14
+ * @param functionsList -> the list of all functions
15
+ */
16
+ export const generateContextData = ({
17
+ user,
18
+ services,
19
+ app,
20
+ rules,
21
+ currentFunction,
22
+ functionsList,
23
+ GenerateContext
24
+ }: GenerateContextDataParams) => ({
25
+ BSON: mongodb.BSON,
26
+ console: {
27
+ log: (...args: Arguments) => {
28
+ console.log(...args)
29
+ }
30
+ },
31
+ context: {
32
+ user,
33
+ environment: {
34
+ tag: process.env.NODE_ENV
35
+ },
36
+ values: {
37
+ get: (key: string) => process.env[key],
38
+ },
39
+ services: {
40
+ get: (serviceName: keyof typeof services) => {
41
+ try {
42
+ return services[serviceName](app, {
43
+ rules,
44
+ user,
45
+ run_as_system: currentFunction.run_as_system
46
+ })
47
+ } catch (error) {
48
+ console.error(
49
+ 'Something went wrong while generating context function',
50
+ serviceName,
51
+ error
52
+ )
53
+ }
54
+ }
55
+ },
56
+ functions: {
57
+ execute: (name: keyof typeof functionsList, ...args: Arguments) => {
58
+ const currentFunction = functionsList[name] as Function
59
+ return GenerateContext({
60
+ args,
61
+ app,
62
+ rules,
63
+ user,
64
+ currentFunction,
65
+ functionsList,
66
+ services
67
+ })
68
+ }
69
+ }
70
+ }
71
+ })
@@ -0,0 +1,52 @@
1
+ import m from 'module'
2
+ import vm from 'vm'
3
+ import { EJSON } from 'bson'
4
+ import { generateContextData } from './helpers'
5
+ import { GenerateContextParams } from './interface'
6
+
7
+ /**
8
+ * > Used to generate the current context
9
+ * @testable
10
+ * @param args -> generic arguments
11
+ * @param app -> the fastify instance
12
+ * @param rules -> the rules object
13
+ * @param user -> the current user
14
+ * @param currentFunction -> the function's name that should be called
15
+ * @param functionsList -> the list of all functions
16
+ * @param services -> the list of all services
17
+ */
18
+ export async function GenerateContext({
19
+ args,
20
+ app,
21
+ rules,
22
+ user,
23
+ currentFunction,
24
+ functionsList,
25
+ services
26
+ }: GenerateContextParams) {
27
+ const contextData = generateContextData({
28
+ user,
29
+ services,
30
+ app,
31
+ rules,
32
+ currentFunction,
33
+ functionsList,
34
+ GenerateContext
35
+ })
36
+
37
+ try {
38
+ vm.runInContext(m.wrap(currentFunction.code), vm.createContext(contextData))(
39
+ exports,
40
+ require,
41
+ module,
42
+ __filename,
43
+ __dirname
44
+ )
45
+ }
46
+ catch (e) {
47
+ console.log(e)
48
+ }
49
+
50
+
51
+ return await module.exports(...EJSON.deserialize(args))
52
+ }