nodester 0.0.1

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 (63) hide show
  1. package/LICENSE +21 -0
  2. package/Readme.md +125 -0
  3. package/docs/App.md +13 -0
  4. package/docs/Queries.md +61 -0
  5. package/docs/Readme.md +2 -0
  6. package/docs/Routing.md +34 -0
  7. package/examples/goal/index.js +23 -0
  8. package/examples/rest/index.js +25 -0
  9. package/examples/rest/node_modules/.package-lock.json +40 -0
  10. package/examples/rest/package-lock.json +72 -0
  11. package/examples/rest/package.json +14 -0
  12. package/lib/application/MiddlewareStack.js +125 -0
  13. package/lib/application/http/request.js +462 -0
  14. package/lib/application/http/response.js +1107 -0
  15. package/lib/application/http/utils.js +254 -0
  16. package/lib/application/index.js +292 -0
  17. package/lib/constants/ConstantsEnum.js +13 -0
  18. package/lib/constants/ResponseFormats.js +7 -0
  19. package/lib/controllers/Controller.js +474 -0
  20. package/lib/controllers/JWTController.js +240 -0
  21. package/lib/controllers/ServiceController.js +109 -0
  22. package/lib/controllers/WebController.js +75 -0
  23. package/lib/facades/Facade.js +388 -0
  24. package/lib/facades/FacadeParams.js +11 -0
  25. package/lib/facades/ServiceFacade.js +17 -0
  26. package/lib/facades/jwt.facade.js +273 -0
  27. package/lib/factories/errors/CustomError.js +22 -0
  28. package/lib/factories/errors/index.js +9 -0
  29. package/lib/factories/responses/api.js +90 -0
  30. package/lib/factories/responses/html.js +55 -0
  31. package/lib/logger/console.js +24 -0
  32. package/lib/models/DisabledRefreshToken.js +68 -0
  33. package/lib/models/Extractor.js +320 -0
  34. package/lib/models/define.js +62 -0
  35. package/lib/models/mixins.js +369 -0
  36. package/lib/policies/Role.js +77 -0
  37. package/lib/policies/RoleExtracting.js +97 -0
  38. package/lib/preprocessors/BodyPreprocessor.js +61 -0
  39. package/lib/preprocessors/IncludesPreprocessor.js +55 -0
  40. package/lib/preprocessors/QueryPreprocessor.js +64 -0
  41. package/lib/routers/Default/index.js +143 -0
  42. package/lib/routers/Default/layer.js +50 -0
  43. package/lib/routers/Main/index.js +10 -0
  44. package/lib/routers/Roles/index.js +81 -0
  45. package/lib/services/includes.service.js +79 -0
  46. package/lib/services/jwt.service.js +147 -0
  47. package/lib/tools/sql.tool.js +82 -0
  48. package/lib/utils/dates.util.js +23 -0
  49. package/lib/utils/forms.util.js +22 -0
  50. package/lib/utils/json.util.js +49 -0
  51. package/lib/utils/mappers/Routes/index.js +100 -0
  52. package/lib/utils/mappers/Routes/utils.js +20 -0
  53. package/lib/utils/modelAssociations.util.js +44 -0
  54. package/lib/utils/objects.util.js +69 -0
  55. package/lib/utils/params.util.js +19 -0
  56. package/lib/utils/path.util.js +26 -0
  57. package/lib/utils/queries.util.js +240 -0
  58. package/lib/utils/sanitizations.util.js +111 -0
  59. package/lib/utils/sql.util.js +78 -0
  60. package/lib/utils/strings.util.js +43 -0
  61. package/lib/utils/types.util.js +26 -0
  62. package/package.json +63 -0
  63. package/tests/index.test.js +35 -0
@@ -0,0 +1,369 @@
1
+ /*
2
+ * CRUD mixins for any model:
3
+ */
4
+ // Utils:
5
+ const {
6
+ modelHasAssociations,
7
+ getModelAssociationProps,
8
+ compileModelAssociationData,
9
+ } = require('nodester/utils/modelAssociations.util');
10
+
11
+
12
+ module.exports = {
13
+ implementsCRUD: _implementsCRUD
14
+ }
15
+
16
+ function _implementsCRUD(modelDefinition) {
17
+ if (!!modelDefinition) {
18
+
19
+ // Create.
20
+ modelDefinition.createWithIncludes = _createWithIncludes.bind(modelDefinition);
21
+
22
+ // Read:
23
+ modelDefinition.findById = _findById.bind(modelDefinition);
24
+ modelDefinition.findOneWithIncludes = _findOneWithIncludes.bind(modelDefinition);
25
+
26
+ // Update:
27
+ modelDefinition.updateOne = _updateOne.bind(modelDefinition);
28
+ modelDefinition.updateById = _updateById.bind(modelDefinition);
29
+
30
+ // Delete.
31
+ modelDefinition.deleteById = _deleteById.bind(modelDefinition);
32
+
33
+ // Associations:
34
+ modelDefinition.getIncludesList = _getIncludesList.bind(modelDefinition);
35
+ }
36
+ }
37
+
38
+ /* Main mixinis: */
39
+ async function _createWithIncludes(
40
+ data={}
41
+ ) {
42
+ try {
43
+ const instance = await this.create(data);
44
+
45
+ if (!instance) {
46
+ const err = new Error(`Failed to create model.`);
47
+ err.name = 'CreateRecordError';
48
+ throw err;
49
+ }
50
+
51
+ // Variable that will contain data from parent instance and associations, mentioned in data.
52
+ let fullInstanceData = instance.toJSON();
53
+
54
+ // If this model has associations:
55
+ if (modelHasAssociations(this)) {
56
+ const allModelAssociations = Object.entries(this.associations);
57
+
58
+ for (const [ associationName, associationDefinition ] of allModelAssociations) {
59
+
60
+ // If data of this association is present:
61
+ if (!!data[associationName]) {
62
+ // Preparation to work with association:
63
+ const {
64
+ associatedModel,
65
+ foreignKey,
66
+ associationType
67
+ } = getModelAssociationProps(associationDefinition, data);
68
+
69
+ // If association type is HasMany or HasOne (We don't work with any other):
70
+ if (associationType === 'HasMany' || associationType === 'HasOne') {
71
+
72
+ // Process current instance.
73
+ const operationsResults = await _updateOrCreateOrDeleteBasedOnAssociationData({
74
+ associatedModel: associatedModel,
75
+ dataOfAssociation: data[associationName],
76
+ parentModelId: instance.id,
77
+ parentForeignKey: foreignKey,
78
+ });
79
+
80
+ fullInstanceData[associationName] =_unwrapUpdateOrCreateOrDeleteOperationsResults(
81
+ operationsResults,
82
+ associationType
83
+ );
84
+ }
85
+
86
+ fullInstanceData[associationName] = fullInstanceData[associationName] ?? data[associationName];
87
+ }
88
+ }
89
+
90
+ }
91
+
92
+ // Variable, that is used by _updateById,
93
+ // but we will also put it here to make API consistent.
94
+ const isNewRecord = true;
95
+ return Promise.resolve([ isNewRecord, fullInstanceData ]);
96
+ }
97
+ catch(error) {
98
+ return Promise.reject(error);
99
+ }
100
+ }
101
+
102
+ function _findById(
103
+ id=null,
104
+ include=[],
105
+ paranoid=true
106
+ ) {
107
+ const query = {
108
+ where: { id },
109
+ include: include,
110
+ paranoid: !!paranoid
111
+ };
112
+ return this.findOne(query);
113
+ }
114
+
115
+ function _findOneWithIncludes(
116
+ where={},
117
+ include=[],
118
+ paranoid=true
119
+ ) {
120
+ const query = {
121
+ where: where,
122
+ include: include,
123
+ paranoid: !!paranoid
124
+ };
125
+ return this.findOne(query);
126
+ }
127
+
128
+ async function _updateOne(
129
+ where,
130
+ data,
131
+ include=[]
132
+ ) {
133
+ try {
134
+ const instance = await this.findOneWithIncludes(where, include);
135
+
136
+ if (!instance) {
137
+ const err = new Error(`Model not found`);
138
+ err.name = 'NotFound';
139
+ throw err;
140
+ }
141
+
142
+ // Update parent model instance:
143
+ instance.set({ ...data });
144
+ const saveResult = await instance.save();
145
+ const { isNewRecord } = saveResult;
146
+
147
+ // Variable that will contain data from parent instance and associations, mentioned in data.
148
+ let fullInstanceData = instance.toJSON();
149
+
150
+ // If this model has associations:
151
+ if (modelHasAssociations(this)) {
152
+
153
+ const associationsEntries = Object.entries(this.associations);
154
+ for (const [ associationName, associationDefinition ] of associationsEntries) {
155
+
156
+ // If data of this association is present:
157
+ if (!!data[associationName]) {
158
+
159
+ // Preparation to work with association:
160
+ const {
161
+ associatedModel,
162
+ foreignKey,
163
+ associationType
164
+ } = getModelAssociationProps(associationDefinition, data);
165
+
166
+ // If association type is HasMany or HasOne (We don't work with any other):
167
+ if (associationType === 'HasMany' || associationType === 'HasOne') {
168
+
169
+ // Process current instance.
170
+ const operationsResults = await _updateOrCreateOrDeleteBasedOnAssociationData({
171
+ associatedModel: associatedModel,
172
+ dataOfAssociation: data[associationName],
173
+ parentModelId: instance.id,
174
+ parentForeignKey: foreignKey,
175
+ });
176
+
177
+ fullInstanceData[associationName] = _unwrapUpdateOrCreateOrDeleteOperationsResults(
178
+ operationsResults,
179
+ associationType
180
+ );
181
+ }
182
+
183
+ fullInstanceData[associationName] = fullInstanceData[associationName] ?? data[associationName];
184
+ }
185
+ }
186
+
187
+ }
188
+
189
+ // Select this instance again, if includes was set:
190
+ if (include?.length > 0) {
191
+ const updatedInstance = await this.findOneWithIncludes(where, include);
192
+ fullInstanceData = updatedInstance.toJSON();
193
+ }
194
+
195
+ return Promise.resolve([ isNewRecord, fullInstanceData ]);
196
+ }
197
+ catch(error) {
198
+ return Promise.reject(error);
199
+ }
200
+ }
201
+
202
+ async function _updateById(
203
+ id=null,
204
+ data={},
205
+ include=[]
206
+ ) {
207
+ const where = { id };
208
+ return this.updateOne(
209
+ where,
210
+ data,
211
+ include
212
+ );
213
+ }
214
+
215
+ function _deleteById(
216
+ id=null
217
+ ) {
218
+ const query = {
219
+ where: { id }
220
+ };
221
+ return this.destroy(query);
222
+ }
223
+ /* Main mixinis\ */
224
+
225
+ /* Association mixins: */
226
+ function _getIncludesList(facadeData=null) {
227
+ // console.log({ facadeData, model: this });
228
+
229
+ const result = [];
230
+
231
+ const associations = this.associations;
232
+ const associationEntries = Object.entries(associations);
233
+
234
+ associationEntries.forEach(([
235
+ associationName,
236
+ associationDefinition
237
+ ]) => {
238
+ const a = { association: associationName };
239
+
240
+ if (!!facadeData) {
241
+ // If facade data is set, go deeper:
242
+ const keys = Object.keys( facadeData );
243
+ if (keys.indexOf(associationName) > 0) {
244
+ const associationModel = associationDefinition.target;
245
+
246
+ const a = { association: associationName };
247
+ if (Object.entries(associationModel.associations).length > 0) {
248
+ const deepData = facadeData[ associationName ];
249
+ a.include = associationModel.getIncludesList(Array.isArray(deepData) ? deepData[0] : deepData);
250
+ }
251
+
252
+ result.push( a );
253
+ }
254
+ }
255
+ else {
256
+ result.push( a );
257
+ }
258
+ });
259
+
260
+ // console.log('getIncludesList', result);
261
+
262
+ return result;
263
+ }
264
+ /* Association mixins\ */
265
+
266
+ /* Subfunctions: */
267
+ async function _updateOrCreateOrDelete(
268
+ modelDefinition,
269
+ data
270
+ ) {
271
+ try {
272
+ let operation = 'skipped';
273
+ let newInstance = null;
274
+
275
+ // If this instance has an id, update it,
276
+ // if no, create from data:
277
+ if (!isNaN(data?.id)) {
278
+ // If marked for deletion, delete:
279
+ if (!!data?.should_delete) {
280
+ operation = 'deleted';
281
+ await _deleteById.bind(modelDefinition)(data.id);
282
+ }
283
+ else {
284
+ operation = 'updated';
285
+ newInstance = await _updateById.bind(modelDefinition)(data.id, data);
286
+ }
287
+ }
288
+ else {
289
+ operation = 'created';
290
+ newInstance = await _createWithIncludes.bind(modelDefinition)(data);
291
+ }
292
+
293
+ return Promise.resolve({
294
+ newInstance,
295
+ operation,
296
+ });
297
+ }
298
+ catch(error) {
299
+ return Promise.reject(error);
300
+ }
301
+ }
302
+
303
+ async function _updateOrCreateOrDeleteBasedOnAssociationData({
304
+ associatedModel,
305
+ dataOfAssociation,
306
+ parentModelId,
307
+ parentForeignKey,
308
+ }) {
309
+ try {
310
+ let result = [];
311
+
312
+ // Detect data type.
313
+ const isSingleInstance = Array.isArray(dataOfAssociation) === false;
314
+
315
+ // If single instance of associated model:
316
+ if (isSingleInstance) {
317
+ const operationResult = await _updateOrCreateOrDelete(
318
+ associatedModel,
319
+ compileModelAssociationData({
320
+ dataOfAssociation,
321
+ parentForeignKey,
322
+ parentModelId,
323
+ })
324
+ );
325
+
326
+ result = [ operationResult ];
327
+ }
328
+ // If multiple instances of associated model:
329
+ else {
330
+ // Update or create each:
331
+ const promises = dataOfAssociation.map(
332
+ (data) => _updateOrCreateOrDelete(
333
+ associatedModel,
334
+ compileModelAssociationData({
335
+ dataOfAssociation: data,
336
+ parentForeignKey: parentForeignKey,
337
+ parentModelId: parentModelId,
338
+ })
339
+ )
340
+ );
341
+
342
+ // Wait untill all instances go through process.
343
+ result = await Promise.all(promises);
344
+ }
345
+
346
+ return Promise.resolve(result);
347
+ }
348
+ catch(error) {
349
+ return Promise.reject(error);
350
+ }
351
+ }
352
+
353
+ function _unwrapUpdateOrCreateOrDeleteOperationsResults(
354
+ operationsResults,
355
+ associationType
356
+ ) {
357
+ // If instance was not deleted, add it to final array.
358
+ const result = operationsResults.filter(({ operation }) => operation !== 'deleted')
359
+ .map(({ newInstance }) => newInstance[1]);
360
+
361
+ // If this association referenced only certain record,
362
+ // unwrap "result" array and send first element:
363
+ if (associationType === 'HasOne') {
364
+ return result[0];
365
+ }
366
+
367
+ return result;
368
+ }
369
+ /* Subfunctions\ */
@@ -0,0 +1,77 @@
1
+ // Reponse protocol generator.
2
+ const APIResponseFactory = require('nodester/factories/responses/api');
3
+
4
+
5
+ module.exports = class RolePolicy {
6
+ constructor({
7
+ roleName,
8
+ jwtFacade,
9
+ apiResponseFactory,
10
+ }) {
11
+ if (!roleName)
12
+ throw new Error('"roleName" argument is invalid.');
13
+
14
+ if (!jwtFacade)
15
+ throw new Error('"jwtFacade" argument is invalid.');
16
+
17
+ this.roleName = roleName;
18
+ this.jwtFacade = jwtFacade;
19
+
20
+ // Init standard API response factory.
21
+ const standardAPIResponseFactory = new APIResponseFactory();
22
+
23
+ // Set response factory:
24
+ this.createOKResponse = apiResponseFactory?.createOKResponse ??
25
+ standardAPIResponseFactory.createOKResponse.bind(standardAPIResponseFactory);;
26
+ this.createErrorResponse = apiResponseFactory?.createErrorResponse ??
27
+ standardAPIResponseFactory.createErrorResponse.bind(standardAPIResponseFactory);;
28
+ }
29
+
30
+ async dryRun(req, res, next) {
31
+ try {
32
+ const jwtService = this.jwtFacade.service;
33
+
34
+ // Get token either from header, query or body.
35
+ const token = jwtService.extractTokenFromRequest(req);
36
+
37
+ // Verifys and parses token. On failed validation will throw error.
38
+ const parsedToken = await jwtService.verifyAccessToken(token);
39
+
40
+ // Check role:
41
+ if (parsedToken.role !== this.roleName) {
42
+ const err = new Error(`Unauthorized.`);
43
+ err.name = 'UnauthorizedError';
44
+ err.status = 401;
45
+ throw err;
46
+ }
47
+
48
+ // Everything's good, procceed:
49
+ req.token = {
50
+ parsed: parsedToken,
51
+ initial: token
52
+ }
53
+
54
+ return Promise.resolve();
55
+ }
56
+ catch(error) {
57
+ // If error is not 401
58
+ // or
59
+ // error is not "NoToken",
60
+ // log it:
61
+ if (
62
+ ['NoToken', 'UnauthorizedError'].indexOf(error?.name) === -1
63
+ ) {
64
+ console.error(`${ this.roleName }.policy error:`, error);
65
+ }
66
+
67
+ const statusCode = error?.status ?? 401;
68
+
69
+ const err = new Error(error.message);
70
+ err.name = error.name ?? 'UnknownError';
71
+ err.details = { message: 'Unauthorized.' }
72
+ err.status = statusCode;
73
+
74
+ return Promise.reject(err);
75
+ }
76
+ }
77
+ }
@@ -0,0 +1,97 @@
1
+ // Format for Role header.
2
+ const CLAIMED_ROLE_HEADER_NAME = 'x-claimed-role';
3
+ // Reponse protocol generator.
4
+ const APIResponseFactory = require('nodester/factories/responses/api');
5
+
6
+
7
+ module.exports = class RoleExtractingPolicy {
8
+ constructor({
9
+ jwtFacade,
10
+ apiResponseFactory,
11
+ name
12
+ }) {
13
+
14
+ if (!jwtFacade)
15
+ throw new Error('"jwtFacade" argument is invalid.');
16
+
17
+ this.jwtFacade = jwtFacade;
18
+ this.name = name ?? 'RoleExtracting';
19
+
20
+ // Init standard API response factory.
21
+ const standardAPIResponseFactory = new APIResponseFactory();
22
+
23
+ // Set response factory:
24
+ this.createOKResponse = apiResponseFactory?.createOKResponse ??
25
+ standardAPIResponseFactory.createOKResponse.bind(standardAPIResponseFactory);;
26
+ this.createErrorResponse = apiResponseFactory?.createErrorResponse ??
27
+ standardAPIResponseFactory.createErrorResponse.bind(standardAPIResponseFactory);;
28
+ }
29
+
30
+ async dryRun(req, res, next) {
31
+ try {
32
+ // Get claimed role.
33
+ const claimedRole = req.header(CLAIMED_ROLE_HEADER_NAME);
34
+
35
+ // If claimed role is not set or it's a visitor:
36
+ if (!claimedRole || claimedRole === 'visitor') {
37
+ // Set role as 'visitor'.
38
+ req.user = { role: 'visitor' };
39
+
40
+ return Promise.resolve();
41
+ }
42
+
43
+ // Unwrap JWT service.
44
+ const jwtService = this.jwtFacade.service;
45
+
46
+ try {
47
+ // Get access token either from header, query or body.
48
+ const token = jwtService.extractTokenFromRequest(req);
49
+
50
+ // Verifys and parses token. On failed validation will throw error.
51
+ const parsedToken = await jwtService.verifyAccessToken(token);
52
+
53
+ // If parsed token's role is not the same as claimed role,
54
+ // immediately throw error:
55
+ if ( parsedToken?.role !== claimedRole ) {
56
+ const err = new Error('Roles do not match');
57
+ err.name = 'RolesMismatch';
58
+ err.details = { message: 'Unauthorized.' }
59
+ err.status = 401;
60
+ return Promise.reject(err);
61
+ }
62
+
63
+ // Everything's good, procceed:
64
+ req.token = {
65
+ parsed: parsedToken,
66
+ initial: token
67
+ }
68
+
69
+ req.user = { role: parsedToken?.role };
70
+ }
71
+ catch(accessTokenError) {
72
+ // If error is not "NoToken", something bad has happened:
73
+ if (accessTokenError?.name !== 'NoToken') {
74
+ throw accessTokenError;
75
+ }
76
+
77
+ // If error is "NoToken":
78
+ // Set role as 'visitor'.
79
+ req.user = { role: 'visitor' };
80
+ }
81
+
82
+ return Promise.resolve();
83
+ }
84
+ catch(error) {
85
+ console.error(`${ this.name }.policy error:`, error);
86
+
87
+ const statusCode = error?.status ?? 401;
88
+
89
+ const err = new Error(error.message);
90
+ err.name = error.name ?? 'UnknownError';
91
+ err.details = { message: 'Unauthorized.' }
92
+ err.status = statusCode;
93
+
94
+ return Promise.reject(err);
95
+ }
96
+ }
97
+ }
@@ -0,0 +1,61 @@
1
+ // Constants.
2
+ const VISITOR = 'visitor';
3
+
4
+ // Custom error.
5
+ const { Err } = require('nodester/factories/errors');
6
+
7
+
8
+ module.exports = class BodyPreprocessor {
9
+ constructor(
10
+ availableParamsForRoles,
11
+ staticParamsForRoles,
12
+ customProcessFunction
13
+ ) {
14
+ this.availableParamsForRoles = availableParamsForRoles ?? {};
15
+ this.staticParamsForRoles = staticParamsForRoles ?? {};
16
+
17
+ this.customProcessFunction = customProcessFunction ? customProcessFunction : ()=>{};
18
+ }
19
+
20
+ async extract(
21
+ req,
22
+ role
23
+ ) {
24
+ try {
25
+ const requestBody = req.body;
26
+
27
+ if (!requestBody || typeof requestBody !== 'object') {
28
+ const err = new Err();
29
+ err.name = 'ValidationError';
30
+ throw err;
31
+ }
32
+
33
+ // Get role or set "visitor"
34
+ const _role = typeof role === 'string' && role.length > 1 ? role : VISITOR;
35
+
36
+ const resultBody = {};
37
+
38
+ const params = this.availableParamsForRoles[_role] ?? [];
39
+ const staticValues = this.staticParamsForRoles[_role] ?? {};
40
+
41
+ params.forEach((param) => {
42
+ // If such param is set in body:
43
+ if (!!requestBody[param]) {
44
+ resultBody[param] = staticValues[param] ?? requestBody[param];
45
+ }
46
+ // If such param is not set, but we have a "static" for it:
47
+ else if (!requestBody[param] && !!staticValues[param]) {
48
+ resultBody[param] = staticValues[param];
49
+ }
50
+ });
51
+
52
+ // Make further preprocessing using customly defined function.
53
+ await this.customProcessFunction.call(this, req, role, resultBody);
54
+
55
+ return Promise.resolve(resultBody);
56
+ }
57
+ catch(error) {
58
+ return Promise.reject(error);
59
+ }
60
+ }
61
+ }
@@ -0,0 +1,55 @@
1
+ // Constants:
2
+ const VISITOR = 'visitor';
3
+ const DefaultAvailableParamsForRoles = { [VISITOR]: [] };
4
+ const DefaultStaticParamsForRoles = { [VISITOR]: [] };
5
+
6
+ // Custom error.
7
+ const { Err } = require('nodester/factories/errors');
8
+
9
+
10
+ module.exports = class IncludesPreprocessor {
11
+
12
+ constructor(
13
+ availableParamsForRoles,
14
+ staticParamsForRoles,
15
+ customProcessFunction=()=>{}
16
+ ) {
17
+ this.availableParamsForRoles = availableParamsForRoles ?? DefaultAvailableParamsForRoles;
18
+ this.staticParamsForRoles = staticParamsForRoles ?? DefaultStaticParamsForRoles;
19
+
20
+ this.customProcessFunction = customProcessFunction ? customProcessFunction : ()=>{};
21
+ }
22
+
23
+ async extract(
24
+ req,
25
+ role
26
+ ) {
27
+ const requestIncludes = req.query?.includes ?? [];
28
+
29
+ if (!requestQuery || typeof requestQuery !== 'object') {
30
+ const err = new Err();
31
+ err.name = 'ValidationError';
32
+ throw err;
33
+ }
34
+
35
+ // Get role or set "visitor"
36
+ const _role = typeof role === 'string' && role.length > 1 ? role : VISITOR;
37
+
38
+ const resultIncludes = [];
39
+
40
+ const params = this.availableParamsForRoles[_role] ?? [];
41
+ const staticValues = this.staticParamsForRoles[_role] ?? [];
42
+
43
+ params.forEach((param) => {
44
+ // If such param is set in query:
45
+ if (requestIncludes.indexOf(param) !== -1) {
46
+ resultIncludes.push(param);
47
+ }
48
+ });
49
+
50
+ // Make further preprocessing using custom defined function.
51
+ await this.customProcessFunction.call(this, req, role, resultIncludes);
52
+
53
+ return resultIncludes;
54
+ }
55
+ }