@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,190 @@
1
+ import { ObjectId } from 'bson';
2
+ import { User } from '../../fastify';
3
+ import { Role } from '../roles/interface';
4
+ import { MachineContext } from '../roles/machines/interface'
5
+ import { checkIsValidFieldNameFn } from '../roles/machines/read/D/validators';
6
+
7
+ const mockUser = {} as User
8
+ const mockId = new ObjectId()
9
+
10
+ describe('checkIsValidFieldNameFn', () => {
11
+ beforeEach(() => {
12
+ jest.clearAllMocks();
13
+ });
14
+ it('should return filtered fields based on role permissions, without excluding _id', () => {
15
+ const mockedRole = {
16
+ name: "test",
17
+ apply_when: {
18
+ "%%true": true
19
+ },
20
+ fields: {
21
+ name: { read: true, write: false },
22
+ email: { read: false, write: true },
23
+ },
24
+ additional_fields: {},
25
+ } as Role
26
+ const context = {
27
+ user: mockUser,
28
+ role: mockedRole,
29
+ params: {
30
+ cursor: { _id: mockId, name: 'Alice', email: 'alice@example.com', age: 25 },
31
+ },
32
+ }
33
+
34
+ const result = checkIsValidFieldNameFn(context as MachineContext);
35
+ expect(result).toEqual({ name: 'Alice', email: 'alice@example.com', _id: mockId });
36
+ });
37
+ it("should exclude _id if role doesn't allows it", () => {
38
+ const mockedRole = {
39
+ name: "test",
40
+ apply_when: {
41
+ "%%true": true
42
+ },
43
+ fields: {
44
+ _id: { read: false, write: false },
45
+ name: { read: true, write: false },
46
+ },
47
+ additional_fields: {},
48
+ } as Role
49
+ const context = {
50
+ user: mockUser,
51
+ role: mockedRole,
52
+ params: {
53
+ cursor: { _id: mockId, name: 'Alice' },
54
+ },
55
+ };
56
+
57
+ const result = checkIsValidFieldNameFn(context as MachineContext);
58
+
59
+ expect(result).toEqual({ name: 'Alice' });
60
+ });
61
+ it("should include _id if write role allows it", () => {
62
+ const mockedRole = {
63
+ name: "test",
64
+ apply_when: {
65
+ "%%true": true
66
+ },
67
+ fields: {
68
+ _id: { read: false, write: true },
69
+ name: { read: true, write: false },
70
+ },
71
+ additional_fields: {},
72
+ } as Role
73
+ const context = {
74
+ user: mockUser,
75
+ role: mockedRole,
76
+ params: {
77
+ cursor: { _id: mockId, name: 'Alice' },
78
+ },
79
+ };
80
+
81
+ const result = checkIsValidFieldNameFn(context as MachineContext);
82
+
83
+ expect(result).toEqual({ _id: mockId, name: 'Alice' });
84
+ });
85
+ it("should include _id if read role allows it", () => {
86
+ const mockedRole = {
87
+ name: "test",
88
+ apply_when: {
89
+ "%%true": true
90
+ },
91
+ fields: {
92
+ _id: { read: true, write: false },
93
+ name: { read: true, write: false },
94
+ },
95
+ additional_fields: {},
96
+ } as Role
97
+ const context = {
98
+ user: mockUser,
99
+ role: mockedRole,
100
+ params: {
101
+ cursor: { _id: mockId, name: 'Alice' },
102
+ },
103
+ };
104
+
105
+ const result = checkIsValidFieldNameFn(context as MachineContext);
106
+
107
+ expect(result).toEqual({ _id: mockId, name: 'Alice' });
108
+ });
109
+
110
+
111
+ it('should return an empty object if no fields are readable/writable', () => {
112
+ const mockedRole = {
113
+ name: "test",
114
+ apply_when: {
115
+ "%%true": true
116
+ },
117
+ fields: {
118
+ name: { read: false, write: false },
119
+ },
120
+ additional_fields: {},
121
+ } as Role
122
+ const context = {
123
+ role: mockedRole,
124
+ params: {
125
+ cursor: { name: 'Charlie', email: 'charlie@example.com' },
126
+ },
127
+ };
128
+
129
+ const result = checkIsValidFieldNameFn(context as MachineContext);
130
+
131
+ expect(result).toEqual({});
132
+ });
133
+
134
+ it('should handle additional_fields correctly for read permission', () => {
135
+ const mockedRole = {
136
+ name: "test",
137
+ apply_when: {
138
+ "%%true": true
139
+ },
140
+ fields: {},
141
+ additional_fields: { phone: { read: true, write: false } },
142
+ } as Role
143
+ const context = {
144
+ role: mockedRole,
145
+ params: {
146
+ cursor: { _id: mockId, phone: '123456789', address: 'Unknown' },
147
+ },
148
+ };
149
+
150
+ const result = checkIsValidFieldNameFn(context as MachineContext);
151
+ expect(result).toEqual({ _id: mockId, phone: '123456789' });
152
+ });
153
+ it('should handle additional_fields correctly for write permission', () => {
154
+ const mockedRole = {
155
+ name: "test",
156
+ apply_when: {
157
+ "%%true": true
158
+ },
159
+ fields: {},
160
+ additional_fields: { phone: { read: false, write: true }, address: { read: false, write: true } },
161
+ } as Role
162
+ const context = {
163
+ role: mockedRole,
164
+ params: {
165
+ cursor: { _id: mockId, phone: '123456789', address: 'Unknown' },
166
+ },
167
+ };
168
+
169
+ const result = checkIsValidFieldNameFn(context as MachineContext);
170
+ expect(result).toEqual({ _id: mockId, phone: '123456789', address: 'Unknown' });
171
+ });
172
+ it('should return only the _id if fields and additional fields are not defined', () => {
173
+ const mockedRole = {
174
+ name: "test",
175
+ apply_when: {
176
+ "%%true": true
177
+ }
178
+ } as Role
179
+ const context = {
180
+ role: mockedRole,
181
+ params: {
182
+ cursor: { _id: mockId, phone: '123456789', address: 'Unknown' },
183
+ },
184
+ };
185
+
186
+ const result = checkIsValidFieldNameFn(context as MachineContext);
187
+ expect(result).toEqual({ _id: mockId });
188
+ });
189
+
190
+ });
@@ -0,0 +1,38 @@
1
+
2
+ import crypto from 'crypto';
3
+ import { promisify } from 'node:util'
4
+ import { comparePassword } from '../crypto';
5
+
6
+ const scrypt = promisify(crypto.scrypt);
7
+
8
+ describe('comparePassword', () => {
9
+ beforeEach(() => {
10
+ jest.clearAllMocks();
11
+ });
12
+ it('should return true for matching passwords', async () => {
13
+ const plaintext = 'mySecretPassword';
14
+ const salt = crypto.randomBytes(16).toString('hex');
15
+ const hashBuffer = (await scrypt(plaintext, salt, 64)) as Buffer;
16
+ const storedPassword = `${hashBuffer.toString('hex')}.${salt}`;
17
+ const result = await comparePassword(plaintext, storedPassword);
18
+ expect(result).toBe(true);
19
+ });
20
+
21
+ it('should return false for non-matching passwords', async () => {
22
+ const plaintext = 'mySecretPassword';
23
+ const wrongPassword = 'wrongPassword';
24
+
25
+ const salt = crypto.randomBytes(16).toString('hex');
26
+ const hashBuffer = (await scrypt(plaintext, salt, 64)) as Buffer;
27
+ const storedPassword = `${hashBuffer.toString('hex')}.${salt}`;
28
+
29
+ const result = await comparePassword(wrongPassword, storedPassword);
30
+ expect(result).toBe(false);
31
+ });
32
+
33
+ it('should throw an error if storedPassword format is incorrect', async () => {
34
+ await expect(comparePassword('anyPassword', 'invalidFormat'))
35
+ .rejects
36
+ .toThrow();
37
+ });
38
+ });
@@ -0,0 +1,57 @@
1
+ import { someAsync } from '../helpers/someAsync';
2
+ import { evaluateExpression } from '../roles/helpers';
3
+ import { MachineContext } from '../roles/machines/interface';
4
+ import { evaluateDocumentFiltersReadFn } from '../roles/machines/read/B/validators';
5
+
6
+ const mockContext = {
7
+ params: { type: 'read' },
8
+ role: { document_filters: { read: 'someFilterExpression' } },
9
+ user: { id: 'user123', name: 'Test User' },
10
+ } as unknown as MachineContext;
11
+
12
+ jest.mock('../helpers/someAsync', () => ({
13
+ someAsync: jest.fn().mockImplementation(async (array: Array<unknown>, callback: (item: unknown) => Promise<boolean>) => {
14
+ for (const item of array) {
15
+ if (await callback(item)) return true;
16
+ }
17
+ return false;
18
+ })
19
+ }));
20
+
21
+ jest.mock('../roles/helpers', () => ({
22
+ evaluateExpression: jest.fn(),
23
+ }));
24
+
25
+ describe('evaluateDocumentFiltersReadFn', () => {
26
+ beforeEach(() => {
27
+ jest.clearAllMocks();
28
+ });
29
+
30
+ it('should return true if at least one filter evaluates to true', async () => {
31
+ (evaluateExpression as jest.Mock).mockResolvedValue(true);
32
+ const result = await evaluateDocumentFiltersReadFn(mockContext);
33
+ expect(result).toBe(true);
34
+ expect(evaluateExpression).toHaveBeenCalledWith(mockContext.params, mockContext.role.document_filters?.read, mockContext.user);
35
+ expect(someAsync).toHaveBeenCalled();
36
+ });
37
+
38
+ it('should return false if no filters evaluate to true', async () => {
39
+ (evaluateExpression as jest.Mock).mockResolvedValue(false);
40
+ const result = await evaluateDocumentFiltersReadFn(mockContext);
41
+ expect(result).toBe(false);
42
+ });
43
+
44
+ it('should return false if role has no read filter', async () => {
45
+ mockContext.role.document_filters = {};
46
+ const result = await evaluateDocumentFiltersReadFn(mockContext);
47
+ expect(result).toBe(false);
48
+ expect(evaluateExpression).not.toHaveBeenCalled();
49
+ });
50
+
51
+ it('should return false if type is not in readOnly', async () => {
52
+ mockContext.params.type = 'write';
53
+ const result = await evaluateDocumentFiltersReadFn(mockContext);
54
+ expect(result).toBe(false);
55
+ expect(evaluateExpression).not.toHaveBeenCalled();
56
+ });
57
+ });
@@ -0,0 +1,57 @@
1
+ import { someAsync } from '../helpers/someAsync';
2
+ import { evaluateExpression } from '../roles/helpers';
3
+ import { MachineContext } from '../roles/machines/interface';
4
+ import { evaluateDocumentFiltersWriteFn } from '../roles/machines/read/B/validators';
5
+
6
+ const mockContext = {
7
+ params: { type: 'write' },
8
+ role: { document_filters: { write: 'someFilterExpression' } },
9
+ user: { id: 'user123', name: 'Test User' },
10
+ } as unknown as MachineContext;
11
+
12
+ jest.mock('../helpers/someAsync', () => ({
13
+ someAsync: jest.fn().mockImplementation(async (array: Array<unknown>, callback: (item: unknown) => Promise<boolean>) => {
14
+ for (const item of array) {
15
+ if (await callback(item)) return true;
16
+ }
17
+ return false;
18
+ })
19
+ }));
20
+
21
+ jest.mock('../roles/helpers', () => ({
22
+ evaluateExpression: jest.fn(),
23
+ }));
24
+
25
+ describe('evaluateDocumentFiltersWriteFn', () => {
26
+ beforeEach(() => {
27
+ jest.clearAllMocks();
28
+ });
29
+
30
+ it('should return true if at least one filter evaluates to true', async () => {
31
+ (evaluateExpression as jest.Mock).mockResolvedValue(true);
32
+ const result = await evaluateDocumentFiltersWriteFn(mockContext);
33
+ expect(result).toBe(true);
34
+ expect(evaluateExpression).toHaveBeenCalledWith(mockContext.params, mockContext.role.document_filters?.write, mockContext.user);
35
+ expect(someAsync).toHaveBeenCalled();
36
+ });
37
+
38
+ it('should return false if no filters evaluate to true', async () => {
39
+ (evaluateExpression as jest.Mock).mockResolvedValue(false);
40
+ const result = await evaluateDocumentFiltersWriteFn(mockContext);
41
+ expect(result).toBe(false);
42
+ });
43
+
44
+ it('should return false if type is not in valid', async () => {
45
+ const mockClone = { ...mockContext, params: { type: 'test' as MachineContext["params"]["type"] } } as MachineContext
46
+ const result = await evaluateDocumentFiltersWriteFn(mockClone);
47
+ expect(result).toBe(false);
48
+ expect(evaluateExpression).not.toHaveBeenCalled();
49
+ });
50
+
51
+ it('should return false if role has no write filter', async () => {
52
+ const mockClone = { ...mockContext, role: { ...mockContext.role, document_filters: {} } } as MachineContext
53
+ const result = await evaluateDocumentFiltersWriteFn(mockClone);
54
+ expect(result).toBe(false);
55
+ expect(evaluateExpression).not.toHaveBeenCalled();
56
+ });
57
+ });
@@ -0,0 +1,58 @@
1
+ import { evaluateExpression } from '../roles/helpers';
2
+ import { Params, Role } from '../roles/interface';
3
+ import { evaluateTopLevelReadFn } from '../roles/machines/read/C/validators';
4
+
5
+ jest.mock('../roles/helpers', () => ({
6
+ evaluateExpression: jest.fn(),
7
+ }));
8
+
9
+ const mockedRole = {} as Role
10
+
11
+ const mockUser = {}
12
+ const mockParams = {
13
+ type: "read"
14
+ } as Params
15
+
16
+ describe('evaluateTopLevelReadFn', () => {
17
+ beforeEach(() => {
18
+ jest.clearAllMocks();
19
+ });
20
+ it('should return false if type is different from read', async () => {
21
+ const isValid = await evaluateTopLevelReadFn({
22
+ role: mockedRole,
23
+ user: mockUser,
24
+ params: { type: "write" } as Params
25
+ })
26
+ expect(isValid).toBe(false)
27
+ expect(evaluateExpression).not.toHaveBeenCalled()
28
+ });
29
+ it('should return undefined if type is read and role read is not defined', async () => {
30
+ const isValid = await evaluateTopLevelReadFn({
31
+ role: mockedRole,
32
+ user: mockUser,
33
+ params: mockParams
34
+ })
35
+ expect(isValid).toBe(undefined)
36
+ expect(evaluateExpression).not.toHaveBeenCalled()
37
+ });
38
+ it('should return false if type is read and role read defined but evaluate expression returns false', async () => {
39
+ (evaluateExpression as jest.Mock).mockResolvedValueOnce(false)
40
+ const isValid = await evaluateTopLevelReadFn({
41
+ role: { ...mockedRole, read: false },
42
+ user: mockUser,
43
+ params: mockParams
44
+ })
45
+ expect(isValid).toBe(false)
46
+ expect(evaluateExpression).toHaveBeenCalledWith(mockParams, false, mockUser)
47
+ });
48
+ it('should return true if type is read and role read defined and evaluate expression returns true', async () => {
49
+ (evaluateExpression as jest.Mock).mockResolvedValueOnce(true)
50
+ const isValid = await evaluateTopLevelReadFn({
51
+ role: { ...mockedRole, read: false },
52
+ user: mockUser,
53
+ params: mockParams
54
+ })
55
+ expect(isValid).toBe(true)
56
+ expect(evaluateExpression).toHaveBeenCalledWith(mockParams, false, mockUser)
57
+ });
58
+ });
@@ -0,0 +1,66 @@
1
+ import { evaluateExpression } from '../roles/helpers';
2
+ import { Params, Role } from '../roles/interface';
3
+ import { evaluateTopLevelWriteFn } from '../roles/machines/read/C/validators';
4
+
5
+ jest.mock('../roles/helpers', () => ({
6
+ evaluateExpression: jest.fn(),
7
+ }));
8
+
9
+ const mockedRole = {} as Role
10
+
11
+ const mockUser = {}
12
+ const mockParams = {
13
+ type: "read"
14
+ } as Params
15
+
16
+ describe('evaluateTopLevelWriteFn', () => {
17
+ it('should return undefined if type is different from read and write', async () => {
18
+ const isValid = await evaluateTopLevelWriteFn({
19
+ role: mockedRole,
20
+ user: mockUser,
21
+ params: { type: "delete" } as Params
22
+ })
23
+ expect(isValid).toBe(undefined)
24
+ expect(evaluateExpression).not.toHaveBeenCalled()
25
+ });
26
+ it('should return false if type is read but evaluate expression returns false', async () => {
27
+ (evaluateExpression as jest.Mock).mockResolvedValueOnce(false)
28
+ const isValid = await evaluateTopLevelWriteFn({
29
+ role: { ...mockedRole, write: false },
30
+ user: mockUser,
31
+ params: mockParams
32
+ })
33
+ expect(isValid).toBe(false)
34
+ expect(evaluateExpression).toHaveBeenCalledWith(mockParams, false, mockUser)
35
+ });
36
+ it('should return true if type is read and evaluate expression returns true', async () => {
37
+ (evaluateExpression as jest.Mock).mockResolvedValueOnce(true)
38
+ const isValid = await evaluateTopLevelWriteFn({
39
+ role: { ...mockedRole, write: false },
40
+ user: mockUser,
41
+ params: mockParams
42
+ })
43
+ expect(isValid).toBe(true)
44
+ expect(evaluateExpression).toHaveBeenCalledWith(mockParams, false, mockUser)
45
+ });
46
+ it('should return false if type is write but evaluate expression returns false', async () => {
47
+ (evaluateExpression as jest.Mock).mockResolvedValueOnce(false)
48
+ const isValid = await evaluateTopLevelWriteFn({
49
+ role: { ...mockedRole, write: false },
50
+ user: mockUser,
51
+ params: { type: "write" } as Params
52
+ })
53
+ expect(isValid).toBe(false)
54
+ expect(evaluateExpression).toHaveBeenCalledWith(mockParams, false, mockUser)
55
+ });
56
+ it('should return true if type is write and evaluate expression returns true', async () => {
57
+ (evaluateExpression as jest.Mock).mockResolvedValueOnce(true)
58
+ const isValid = await evaluateTopLevelWriteFn({
59
+ role: { ...mockedRole, write: false },
60
+ user: mockUser,
61
+ params: { type: "write" } as Params
62
+ })
63
+ expect(isValid).toBe(true)
64
+ expect(evaluateExpression).toHaveBeenCalledWith(mockParams, false, mockUser)
65
+ });
66
+ });
@@ -0,0 +1,65 @@
1
+ import Fastify, { FastifyInstance } from 'fastify'
2
+ import { API_VERSION } from '../../constants'
3
+ import { exposeRoutes } from '../initializer/exposeRoutes'
4
+
5
+ jest.mock('../../constants', () => ({
6
+ API_VERSION: '/api/client/v2'
7
+ }))
8
+
9
+ const config: {
10
+ app?: FastifyInstance
11
+ } = {}
12
+
13
+ describe('exposeRoutes', () => {
14
+
15
+ beforeAll(async () => {
16
+ config.app = Fastify()
17
+ await exposeRoutes(config.app)
18
+ await config.app.ready()
19
+ jest.clearAllMocks();
20
+ })
21
+
22
+ afterAll(async () => {
23
+ await config.app!.close()
24
+ })
25
+
26
+ it('GET /health should return status ok and uptime', async () => {
27
+ const response = await config.app!.inject({
28
+ method: 'GET',
29
+ url: '/health',
30
+ })
31
+ expect(response.statusCode).toBe(200)
32
+ const body = JSON.parse(response.body)
33
+ expect(body).toHaveProperty('status', 'ok')
34
+ expect(body).toHaveProperty('uptime')
35
+ expect(typeof body.uptime).toBe('number')
36
+ })
37
+
38
+ it(`GET ${API_VERSION}/app/:appId/location should return correct location data`, async () => {
39
+ const appId = 'it'
40
+ const response = await config.app!.inject({
41
+ method: 'GET',
42
+ url: `${API_VERSION}/app/${appId}/location`,
43
+ })
44
+
45
+ expect(response.statusCode).toBe(200)
46
+ expect(JSON.parse(response.body)).toEqual({
47
+ deployment_model: 'LOCAL',
48
+ location: 'IE',
49
+ hostname: 'http://localhost:3000',
50
+ ws_hostname: 'wss://localhost:3000'
51
+ })
52
+ })
53
+
54
+ it('exposeRoutes should handle errors in the catch block', async () => {
55
+ const mockedApp = Fastify()
56
+ // Forced fail on get method
57
+ jest.spyOn(mockedApp, 'get').mockImplementation(() => {
58
+ throw new Error('Route registration failed')
59
+ })
60
+ const mockErrorLog = jest.spyOn(console, 'error').mockImplementation(() => { })
61
+ await exposeRoutes(mockedApp)
62
+ expect(mockErrorLog).toHaveBeenCalledWith('Error while exposing routes', 'Route registration failed')
63
+ mockErrorLog.mockRestore()
64
+ })
65
+ })
@@ -0,0 +1,75 @@
1
+ import Fastify from 'fastify'
2
+ import { User } from '../../auth/dtos';
3
+ import { Functions } from '../../features/functions/interface';
4
+ import { Rules } from '../../features/rules/interface'
5
+ import { services } from "../../services";
6
+ import { generateContextData } from "../context/helpers";
7
+
8
+ const originalEnv = process.env;
9
+
10
+ jest.mock('../../services', () => ({
11
+ services: {
12
+ api: jest.fn(),
13
+ aws: jest.fn(),
14
+ 'mongodb-atlas': jest.fn(),
15
+ },
16
+ }));
17
+
18
+ const mockFunctions = {
19
+ test: {
20
+ name: "test",
21
+ code: "test"
22
+ }
23
+ } as Functions
24
+
25
+ const currentFunction = mockFunctions.test
26
+ const GenerateContextMock = jest.fn()
27
+ const mockUser = {} as User
28
+ const mockRules = {} as Rules
29
+ const mockEnv = {
30
+ ...originalEnv,
31
+ test: "someTestVariable",
32
+ NODE_ENV: "dev",
33
+ };
34
+
35
+
36
+ describe('generateContextData', () => {
37
+ beforeEach(() => {
38
+ jest.resetModules();
39
+ process.env = mockEnv
40
+ jest.clearAllMocks();
41
+ });
42
+
43
+ afterEach(() => {
44
+ process.env = originalEnv;
45
+ });
46
+
47
+ it('should return an object with context configuration', async () => {
48
+
49
+ const mockApp = Fastify()
50
+ const { context, console: contextConsole } = generateContextData({ services, app: mockApp, functionsList: mockFunctions, currentFunction, GenerateContext: GenerateContextMock, user: mockUser, rules: mockRules })
51
+ expect(context.user).toEqual(mockUser)
52
+
53
+ const testVariable = context.values.get("test")
54
+ expect(testVariable).toBe(mockEnv.test)
55
+
56
+ expect(context.environment.tag).toBe(mockEnv.NODE_ENV)
57
+
58
+ expect(context.user).toEqual(mockUser)
59
+
60
+ const mockedLog = jest.spyOn(console, 'log').mockImplementation(() => { });
61
+ contextConsole.log('Test', 'generateContextData')
62
+ expect(mockedLog).toHaveBeenCalledWith('Test', 'generateContextData');
63
+ mockedLog.mockRestore();
64
+
65
+ context.services.get("api")
66
+ expect(services.api).toHaveBeenCalled()
67
+ const mockErrorLog = jest.spyOn(console, 'error').mockImplementation(() => { })
68
+ context.services.get("notfound" as keyof typeof services)
69
+ expect(mockErrorLog).toHaveBeenCalled()
70
+ mockErrorLog.mockRestore()
71
+
72
+ context.functions.execute("test")
73
+ expect(GenerateContextMock).toHaveBeenCalled()
74
+ });
75
+ });
@@ -0,0 +1,29 @@
1
+ import rulesMatcherUtils from "../rules-matcher/utils";
2
+
3
+ describe('getDefaultRule', () => {
4
+
5
+ it('should return the default rule', () => {
6
+ expect(rulesMatcherUtils.getDefaultRule(2)).toEqual({ op: '$eq', value: 2 })
7
+ expect(rulesMatcherUtils.getDefaultRule("test")).toEqual({ op: '$eq', value: "test" })
8
+ expect(rulesMatcherUtils.getDefaultRule(true)).toEqual({ op: '$exists', value: true })
9
+ expect(rulesMatcherUtils.getDefaultRule(["test"])).toEqual({ op: '$in', value: ["test"] })
10
+ expect(rulesMatcherUtils.getDefaultRule({ name: "John" })).toEqual({
11
+ name: "John",
12
+ op: "name",
13
+ value: "John"
14
+ })
15
+ expect(rulesMatcherUtils.getDefaultRule({ name: "John", value: "test" })).toEqual({
16
+ name: "John",
17
+ op: "name",
18
+ value: "test"
19
+ })
20
+ expect(rulesMatcherUtils.getDefaultRule({ name: "John", value: "test", op: "$in" })).toEqual({
21
+ name: "John",
22
+ op: "$in",
23
+ value: "test"
24
+ })
25
+ expect(rulesMatcherUtils.getDefaultRule(undefined)).toEqual({ op: '$eq', value: undefined })
26
+ });
27
+
28
+
29
+ });
@@ -0,0 +1,12 @@
1
+ import rulesMatcherUtils from "../rules-matcher/utils";
2
+
3
+ describe('getKey function', () => {
4
+ it('should handle a basic rule correctly', () => {
5
+ const mockKeys = {}
6
+ const mockOptions = { prefix: 'user' }
7
+ const block = { name: { $eq: 'John' } };
8
+ const response = rulesMatcherUtils.getKey(block, mockKeys, mockOptions);
9
+ expect(response).toBe(true)
10
+ expect(mockKeys).toEqual({ "user.name": true })
11
+ });
12
+ });
@@ -0,0 +1,11 @@
1
+ import rulesMatcherUtils from "../rules-matcher/utils";
2
+
3
+ describe('getKeys', () => {
4
+
5
+ it('should handle $and operator correctly', () => {
6
+ expect(rulesMatcherUtils.getKeys(undefined)).toBe(null)
7
+ expect(rulesMatcherUtils.getKeys(() => { })).toEqual([])
8
+ // NOTE -> this cast is forced to test a case that should never be verified
9
+ expect(rulesMatcherUtils.getKeys("test" as unknown as Record<string, unknown>)).toEqual(null)
10
+ });
11
+ });