@adaptivestone/framework 3.4.3 → 4.0.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (52) hide show
  1. package/CHANGELOG.md +30 -0
  2. package/LICENCE +21 -0
  3. package/cluster.js +3 -3
  4. package/commands/CreateUser.js +27 -0
  5. package/commands/Documentation.js +1 -1
  6. package/commands/GetOpenApiJson.js +53 -23
  7. package/commands/migration/Create.js +2 -2
  8. package/config/auth.js +1 -1
  9. package/config/i18n.js +4 -3
  10. package/config/mail.js +5 -1
  11. package/controllers/Home.js +2 -2
  12. package/controllers/Home.test.js +11 -0
  13. package/controllers/index.js +15 -15
  14. package/folderConfig.js +1 -1
  15. package/helpers/yup.js +24 -0
  16. package/index.js +8 -0
  17. package/models/User.js +38 -27
  18. package/models/User.test.js +68 -18
  19. package/modules/AbstractController.js +144 -208
  20. package/modules/AbstractModel.js +2 -1
  21. package/modules/Base.js +3 -2
  22. package/modules/BaseCli.js +6 -2
  23. package/package.json +18 -14
  24. package/server.d.ts +1 -1
  25. package/server.js +25 -8
  26. package/services/cache/Cache.d.ts +3 -3
  27. package/services/cache/Cache.js +17 -3
  28. package/services/documentation/DocumentationGenerator.js +171 -0
  29. package/services/http/HttpServer.js +16 -96
  30. package/services/http/middleware/AbstractMiddleware.js +20 -0
  31. package/services/http/middleware/GetUserByToken.js +4 -0
  32. package/services/http/middleware/I18n.js +119 -0
  33. package/services/http/middleware/I18n.test.js +77 -0
  34. package/services/http/middleware/Pagination.js +56 -0
  35. package/services/http/middleware/PrepareAppInfo.test.js +22 -0
  36. package/services/http/middleware/{Middlewares.test.js → RateLimiter.test.js} +1 -1
  37. package/services/http/middleware/RequestLogger.js +22 -0
  38. package/services/http/middleware/RequestParser.js +36 -0
  39. package/services/messaging/email/index.js +141 -41
  40. package/services/messaging/email/resources/.gitkeep +1 -0
  41. package/services/validate/ValidateService.js +161 -0
  42. package/services/validate/ValidateService.test.js +105 -0
  43. package/services/validate/drivers/AbstractValidator.js +37 -0
  44. package/services/validate/drivers/CustomValidator.js +52 -0
  45. package/services/validate/drivers/YupValidator.js +103 -0
  46. package/tests/setup.js +2 -0
  47. package/services/messaging/email/templates/emptyTemplate/style.less +0 -0
  48. package/services/messaging/email/templates/password/html.handlebars +0 -13
  49. package/services/messaging/email/templates/password/style.less +0 -0
  50. package/services/messaging/email/templates/password/subject.handlebars +0 -1
  51. package/services/messaging/email/templates/password/text.handlebars +0 -1
  52. package/services/messaging/email/templates/verification/style.less +0 -0
@@ -1,19 +1,17 @@
1
- /* eslint-disable array-callback-return */
2
1
  /* eslint-disable no-restricted-syntax */
3
2
  /* eslint-disable guard-for-in */
4
3
  const express = require('express');
5
- const merge = require('deepmerge');
6
-
7
4
  const Base = require('./Base');
8
5
  const GetUserByToken = require('../services/http/middleware/GetUserByToken');
9
6
  const Auth = require('../services/http/middleware/Auth');
10
-
7
+ const ValidateService = require('../services/validate/ValidateService');
8
+ const DocumentationGenerator = require('../services/documentation/DocumentationGenerator');
11
9
  /**
12
10
  * Abstract controller. You should extend any controller from them.
13
11
  * Place you cintroller into controller folder and it be inited in auto way.
14
12
  * By default name of route will be controller name not file name. But please name it in same ways.
15
13
  * You can overwrite base controllers byt creating controllers with tha same file name (yes file name, not class name)
16
- * In most cases you will want to have a 'home' route that not include controller name. For this case please check 'getExpressPath'
14
+ * In most cases you will want to have a 'home' route that not include controller name. For this case please check ' getHttpPath'
17
15
  */
18
16
  class AbstractController extends Base {
19
17
  constructor(app, prefix, isExpressMergeParams = false) {
@@ -24,7 +22,14 @@ class AbstractController extends Base {
24
22
  mergeParams: isExpressMergeParams,
25
23
  });
26
24
  const { routes } = this;
27
- const expressPath = this.getExpressPath();
25
+ let httpPath = this.getHttpPath();
26
+
27
+ if (this.getExpressPath) {
28
+ this.logger.warn(
29
+ `getExpressPath deprecated. Please use getHttpPath instead. Will be removed on v5`,
30
+ );
31
+ httpPath = this.getExpressPath();
32
+ }
28
33
 
29
34
  /**
30
35
  * Grab route middleware onlo one Map
@@ -47,69 +52,15 @@ class AbstractController extends Base {
47
52
  });
48
53
  });
49
54
 
50
- /**
51
- * Parse middlewares to be an object.
52
- */
53
- const parseMiddlewares = (middlewareMap) => {
54
- const middlewaresInfo = [];
55
- // eslint-disable-next-line prefer-const
56
- for (let [path, middleware] of middlewareMap) {
57
- if (!Array.isArray(middleware)) {
58
- middleware = [middleware];
59
- }
60
- for (const M of middleware) {
61
- let method = 'all';
62
- let realPath = path;
63
- if (typeof realPath !== 'string') {
64
- this.logger.error(`Path not a string ${realPath}. Please check it`);
65
- // eslint-disable-next-line no-continue
66
- continue;
67
- }
68
- if (!realPath.startsWith('/')) {
69
- method = realPath.split('/')[0]?.toLowerCase();
70
- if (!method) {
71
- this.logger.error(`Method not found for ${realPath}`);
72
- // eslint-disable-next-line no-continue
73
- continue;
74
- }
75
- realPath = realPath.substring(method.length);
76
- }
77
- if (typeof this.router[method] !== 'function') {
78
- this.logger.error(
79
- `Method ${method} not exist for middleware. Please check your codebase`,
80
- );
81
- // eslint-disable-next-line no-continue
82
- continue;
83
- }
84
- const fullPath = `/${expressPath}/${realPath.toUpperCase()}`
85
- .split('//')
86
- .join('/')
87
- .split('//')
88
- .join('/');
89
- let MiddlewareFunction = M;
90
- let middlewareParams = {};
91
- if (Array.isArray(M)) {
92
- [MiddlewareFunction, middlewareParams] = M;
93
- }
94
-
95
- middlewaresInfo.push({
96
- name: MiddlewareFunction.name,
97
- method,
98
- path: realPath,
99
- fullPath,
100
- params: middlewareParams,
101
- authParams: new MiddlewareFunction(this.app, middlewareParams)
102
- ?.usedAuthParameters,
103
- MiddlewareFunction,
104
- });
105
- }
106
- }
107
- return middlewaresInfo;
108
- };
109
-
110
- const routeMiddlewaresReg = parseMiddlewares(routeMiddlewares);
55
+ const routeMiddlewaresReg = this.parseMiddlewares(
56
+ routeMiddlewares,
57
+ httpPath,
58
+ );
59
+ const middlewaresInfo = this.parseMiddlewares(
60
+ this.constructor.middleware,
61
+ httpPath,
62
+ );
111
63
 
112
- const middlewaresInfo = parseMiddlewares(this.constructor.middleware);
113
64
  const routesInfo = [];
114
65
 
115
66
  /**
@@ -141,11 +92,13 @@ class AbstractController extends Base {
141
92
  (middleware) =>
142
93
  middleware.path === path && middleware.method === verb,
143
94
  );
95
+
144
96
  let routeObject = routes[verb][path];
145
97
  if (Object.prototype.toString.call(routeObject) !== '[object Object]') {
146
98
  routeObject = {
147
99
  handler: routeObject,
148
100
  request: null,
101
+ query: null,
149
102
  middleware: null,
150
103
  };
151
104
 
@@ -165,7 +118,7 @@ class AbstractController extends Base {
165
118
  fnName = fnName.name;
166
119
  }
167
120
 
168
- const fullPath = `/${expressPath}/${path}`
121
+ const fullPath = `/${httpPath}/${path}`
169
122
  .split('//')
170
123
  .join('/')
171
124
  .split('//')
@@ -176,6 +129,7 @@ class AbstractController extends Base {
176
129
  description: routeObject?.description,
177
130
  method: verb.toUpperCase(),
178
131
  fields: routeObject?.request?.fields,
132
+ queryFields: routeObject?.query?.fields,
179
133
  path,
180
134
  fullPath,
181
135
  });
@@ -192,61 +146,51 @@ class AbstractController extends Base {
192
146
  new MiddlewareFunction(this.app, params).getMiddleware(),
193
147
  );
194
148
  }
195
- const { controllerValidationAbortEarly } =
196
- this.app.getConfig('validate');
149
+
197
150
  this.router[verb](
198
151
  path,
199
152
  additionalMiddlewares || [],
200
153
  async (req, res, next) => {
201
- if (routeObject.request) {
202
- if (typeof routeObject.request.validate !== 'function') {
203
- this.logger.error('request.validate should be a function');
204
- }
205
- if (typeof routeObject.request.cast !== 'function') {
206
- this.logger.error('request.cast should be a function');
207
- }
208
- const bodyAndQuery = merge(req.query, req.body);
209
-
210
- try {
211
- await routeObject.request.validate(bodyAndQuery, {
212
- abortEarly: controllerValidationAbortEarly,
213
- req,
214
- });
215
- } catch (e) {
216
- let { errors } = e;
217
- // translate it
218
- if (req.i18n && errors) {
219
- errors = errors.map((err) => req.i18n.t(err));
220
- }
221
- this.logger.error(
222
- `Request validation failed with message: ${e.message}. errors: ${errors}`,
223
- );
224
-
225
- const errorAnswer = {};
226
- if (!e.inner || !e.inner.length) {
227
- errorAnswer[e.path] = errors;
228
- } else {
229
- e.inner.forEach((err) => {
230
- errorAnswer[err.path] = err.errors;
231
- if (req.i18n && err.errors) {
232
- errorAnswer[err.path] = err.errors.map((err1) =>
233
- req.i18n.t(err1),
234
- );
235
- }
236
- });
237
- }
238
-
239
- return res.status(400).json({
240
- errors: errorAnswer,
241
- });
242
- }
243
- req.appInfo.request = await routeObject.request.cast(
244
- bodyAndQuery,
245
- {
246
- stripUnknown: true,
247
- req,
154
+ const requestObj = {
155
+ query: req.query,
156
+ body: req.body,
157
+ appInfo: req.appInfo,
158
+ };
159
+ try {
160
+ req.appInfo.request = await new ValidateService(
161
+ this.app,
162
+ routeObject?.request,
163
+ ).validateReqData(requestObj, {
164
+ selectedReqData: req.body,
165
+ additionalMiddlewareFieldsData: {
166
+ middlewaresInfo,
167
+ routeMiddlewaresReg,
168
+ options: {
169
+ method: verb,
170
+ path: fullPath,
171
+ prefix: 'request',
172
+ },
248
173
  },
249
- );
174
+ });
175
+ req.appInfo.query = await new ValidateService(
176
+ this.app,
177
+ routeObject?.query,
178
+ ).validateReqData(requestObj, {
179
+ selectedReqData: req.query,
180
+ additionalMiddlewareFieldsData: {
181
+ middlewaresInfo,
182
+ routeMiddlewaresReg,
183
+ options: {
184
+ method: verb,
185
+ path: fullPath,
186
+ prefix: 'query',
187
+ },
188
+ },
189
+ });
190
+ } catch (err) {
191
+ return res.status(400).json({
192
+ errors: err.message,
193
+ });
250
194
  }
251
195
  req.body = new Proxy(req.body, {
252
196
  get: (target, prop) => {
@@ -256,6 +200,14 @@ class AbstractController extends Base {
256
200
  return target[prop];
257
201
  },
258
202
  });
203
+ req.query = new Proxy(req.query, {
204
+ get: (target, prop) => {
205
+ this.logger.warn(
206
+ 'Please not use "req.query" directly. Implement "query" and use "req.appInfo.query" ',
207
+ );
208
+ return target[prop];
209
+ },
210
+ });
259
211
 
260
212
  if (!routeObject.handler) {
261
213
  this.logger.error(`Route object have no handler defined`);
@@ -276,6 +228,7 @@ class AbstractController extends Base {
276
228
  }
277
229
  return routeObject.handler.call(this, req, res, next).catch((e) => {
278
230
  this.logger.error(e.message);
231
+ // eslint-disable-next-line no-console
279
232
  console.error(e);
280
233
  return res.status(500).json({
281
234
  message:
@@ -311,104 +264,87 @@ class AbstractController extends Base {
311
264
  text.push(`Time: ${Date.now() - time} ms`);
312
265
 
313
266
  this.logger.verbose(text.join('\n'));
267
+ this.loadedTime = Date.now() - time;
314
268
 
315
269
  /**
316
270
  * Generate documentation
317
271
  */
272
+ if (!this.app.httpServer) {
273
+ this.app.documentation.push(
274
+ DocumentationGenerator.convertDataToDocumentationElement(
275
+ this.getConstructorName(),
276
+ routesInfo,
277
+ middlewaresInfo,
278
+ routeMiddlewaresReg,
279
+ ),
280
+ );
281
+ } else {
282
+ this.app.httpServer.express.use(httpPath, this.router);
283
+ }
284
+ }
318
285
 
319
- const processingFields = (fieldsByRoute) => {
320
- const fields = [];
321
- if (!fieldsByRoute) {
322
- return fields;
286
+ /**
287
+ * Parse middlewares to be an object.
288
+ */
289
+ parseMiddlewares(middlewareMap, httpPath) {
290
+ const middlewaresInfo = [];
291
+ // eslint-disable-next-line prefer-const
292
+ for (let [path, middleware] of middlewareMap) {
293
+ if (!Array.isArray(middleware)) {
294
+ middleware = [middleware];
323
295
  }
324
- const entries = Object.entries(fieldsByRoute);
325
- entries.forEach(([key, value]) => {
326
- const field = {};
327
- field.name = key;
328
- field.type = value.type;
329
- if (value.exclusiveTests) {
330
- field.isRequired = value.exclusiveTests.required;
296
+ for (const M of middleware) {
297
+ let method = 'all';
298
+ let realPath = path;
299
+ if (typeof realPath !== 'string') {
300
+ this.logger.error(`Path not a string ${realPath}. Please check it`);
301
+ // eslint-disable-next-line no-continue
302
+ continue;
331
303
  }
332
- if (value?.innerType) {
333
- field.innerType = value?.innerType?.type;
304
+ if (!realPath.startsWith('/')) {
305
+ method = realPath.split('/')[0]?.toLowerCase();
306
+ if (!method) {
307
+ this.logger.error(`Method not found for ${realPath}`);
308
+ // eslint-disable-next-line no-continue
309
+ continue;
310
+ }
311
+ realPath = realPath.substring(method.length);
334
312
  }
335
-
336
- if (value.fields) {
337
- field.fields = [];
338
- // eslint-disable-next-line no-shadow
339
- const entries = Object.entries(value.fields);
340
- // eslint-disable-next-line no-shadow
341
- entries.forEach(([key, value]) => {
342
- field.fields.push({
343
- name: key,
344
- type: value.type,
345
- });
346
- });
313
+ if (typeof this.router[method] !== 'function') {
314
+ this.logger.error(
315
+ `Method ${method} not exist for middleware. Please check your codebase`,
316
+ );
317
+ // eslint-disable-next-line no-continue
318
+ continue;
319
+ }
320
+ const fullPath = `/${httpPath}/${realPath.toUpperCase()}`
321
+ .split('//')
322
+ .join('/')
323
+ .split('//')
324
+ .join('/');
325
+ let MiddlewareFunction = M;
326
+ let middlewareParams = {};
327
+ if (Array.isArray(M)) {
328
+ [MiddlewareFunction, middlewareParams] = M;
347
329
  }
348
- fields.push(field);
349
- });
350
- return fields;
351
- };
352
-
353
- if (!this.app.httpServer) {
354
- this.app.documentation.push({
355
- contollerName: this.getConstructorName(),
356
- routesInfo: routesInfo.map((route) => ({
357
- [route.fullPath]: {
358
- method: route.method,
359
- name: route.name,
360
- description: route?.description,
361
- fields: processingFields(route.fields),
362
- routeMiddlewares: routeMiddlewaresReg
363
- // eslint-disable-next-line consistent-return
364
- .map((middleware) => {
365
- const routeFullPath = route.fullPath.toUpperCase();
366
- const middlewareFullPath = middleware.fullPath.toUpperCase();
367
- if (
368
- route.method.toLowerCase() ===
369
- middleware.method.toLowerCase() &&
370
- (middlewareFullPath === routeFullPath ||
371
- middlewareFullPath === `${routeFullPath}*`)
372
- ) {
373
- return {
374
- name: middleware.name,
375
- params: middleware.params,
376
- authParams: middleware.authParams,
377
- };
378
- }
379
- })
380
- .filter(Boolean),
381
- controllerMiddlewares: [
382
- ...new Set(
383
- middlewaresInfo
384
- .filter((middleware) => {
385
- const routeFullPath = route.fullPath.toUpperCase();
386
- const middlewareFullPath =
387
- middleware.fullPath.toUpperCase();
388
- const middlewareFullPathWithSliced = middleware.fullPath
389
- .toUpperCase()
390
- .slice(0, -1);
391
330
 
392
- return (
393
- middlewareFullPath === routeFullPath ||
394
- middlewareFullPath === `${routeFullPath}*` ||
395
- routeFullPath?.indexOf(middlewareFullPathWithSliced) !==
396
- -1
397
- );
398
- })
399
- .map(({ name, params, authParams }) => ({
400
- name,
401
- params,
402
- authParams,
403
- })),
404
- ),
405
- ],
406
- },
407
- })),
408
- });
409
- } else {
410
- this.app.httpServer.express.use(expressPath, this.router);
331
+ middlewaresInfo.push({
332
+ name: MiddlewareFunction.name,
333
+ method,
334
+ path: realPath,
335
+ fullPath,
336
+ params: middlewareParams,
337
+ relatedQueryParameters: new MiddlewareFunction(
338
+ this.app,
339
+ middlewareParams,
340
+ )?.relatedQueryParameters,
341
+ authParams: new MiddlewareFunction(this.app, middlewareParams)
342
+ ?.usedAuthParameters,
343
+ MiddlewareFunction,
344
+ });
345
+ }
411
346
  }
347
+ return middlewaresInfo;
412
348
  }
413
349
 
414
350
  /**
@@ -460,9 +396,9 @@ class AbstractController extends Base {
460
396
  }
461
397
 
462
398
  /**
463
- * Get express path with inheritance of path
399
+ * Get http path with inheritance of path
464
400
  */
465
- getExpressPath() {
401
+ getHttpPath() {
466
402
  return `/${this.getConstructorName().toLowerCase()}`.replace('//', '/');
467
403
  }
468
404
 
@@ -3,12 +3,13 @@ const Base = require('./Base');
3
3
 
4
4
  class AbstractModel extends Base {
5
5
  /**
6
- * @param {import('../Server')} app //TODO change to *.d.ts as this is a Server, not app
6
+ * @param {import('../server')} app //TODO change to *.d.ts as this is a Server, not app
7
7
  * @param function callback optional callback when connection ready
8
8
  */
9
9
  constructor(app, callback = () => {}) {
10
10
  super(app);
11
11
  this.mongooseSchema = mongoose.Schema(this.modelSchema);
12
+ mongoose.set('strictQuery', true);
12
13
  this.mongooseSchema.set('timestamps', true);
13
14
  this.mongooseSchema.set('minimize', false);
14
15
  this.mongooseSchema.loadClass(this.constructor);
package/modules/Base.js CHANGED
@@ -1,5 +1,5 @@
1
- const fs = require('fs').promises;
2
- const { join, normalize } = require('path');
1
+ const fs = require('node:fs').promises;
2
+ const { join, normalize } = require('node:path');
3
3
 
4
4
  class Base {
5
5
  #realLogger = null;
@@ -77,6 +77,7 @@ class Base {
77
77
  if (!IsConstructor(Tr) && Tr.default) {
78
78
  Tr = Tr.default;
79
79
  } else {
80
+ // eslint-disable-next-line no-console
80
81
  console.error(
81
82
  `${log.transport} not a constructor. Please check it`,
82
83
  );
@@ -1,4 +1,5 @@
1
- const path = require('path');
1
+ /* eslint-disable no-console */
2
+ const path = require('node:path');
2
3
  const Base = require('./Base');
3
4
 
4
5
  class Cli extends Base {
@@ -46,9 +47,12 @@ class Cli extends Base {
46
47
  );
47
48
  return false;
48
49
  }
50
+ // TODO wait until https://github.com/nodejs/node/issues/35889
51
+ // const { default: Command } = await import(this.commands[command]);
49
52
 
50
- // eslint-disable-next-line global-require, import/no-dynamic-require
53
+ // eslint-disable-next-line import/no-dynamic-require, global-require
51
54
  const Command = require(this.commands[command]);
55
+
52
56
  const c = new Command(this.app, this.commands, args);
53
57
  let result = false;
54
58
 
package/package.json CHANGED
@@ -1,10 +1,10 @@
1
1
  {
2
2
  "name": "@adaptivestone/framework",
3
- "version": "3.4.3",
3
+ "version": "4.0.0",
4
4
  "description": "Adaptive stone node js framework",
5
- "main": "src/index.js",
5
+ "main": "index.js",
6
6
  "engines": {
7
- "node": ">=16.0.0"
7
+ "node": ">=18.0.0"
8
8
  },
9
9
  "repository": {
10
10
  "type": "git",
@@ -15,9 +15,14 @@
15
15
  "dev": "nodemon ./index.js",
16
16
  "prod": "nodemon ./cluster.js",
17
17
  "test": "jest --coverage=true",
18
- "codestyle": "prettier --check '**/*.(js|jsx|ts|tsx|json|css|scss|md)'",
18
+ "prettier": "prettier --check '**/*.(js|jsx|ts|tsx|json|css|scss|md)'",
19
+ "lint": "eslint '**/*.js'",
20
+ "lint:fix": "eslint '**/*.js' --fix",
21
+ "codestyle": "npm run prettier && npm run lint",
19
22
  "prepare": "husky install",
20
- "cli": "node cliCommand"
23
+ "cli": "node cliCommand",
24
+ "benchmark": "h2load -n 10000 -c 50 -p 'http/1.1' http://localhost:3300/",
25
+ "benchmark2": "h2load -n 10000 -c 50 https://localhost:3300/"
21
26
  },
22
27
  "jest": {
23
28
  "setupFilesAfterEnv": [
@@ -34,18 +39,18 @@
34
39
  "author": "Andrey Logunov",
35
40
  "license": "MIT",
36
41
  "dependencies": {
37
- "bcrypt": "^5.0.1",
38
42
  "cors": "^2.8.5",
39
43
  "deepmerge": "^4.2.2",
40
44
  "dotenv": "^16.0.0",
41
- "email-templates": "^10.0.0",
42
45
  "express": "^4.17.1",
43
- "i18next": "^22.0.4",
46
+ "formidable": "^2.1.1",
47
+ "html-to-text": "^9.0.3",
48
+ "i18next": "^23.2.8",
44
49
  "i18next-chained-backend": "^4.0.0",
45
50
  "i18next-fs-backend": "^2.0.0",
46
- "i18next-http-middleware": "^3.1.4",
51
+ "juice": "^9.0.0",
47
52
  "minimist": "^1.2.5",
48
- "mongoose": "^6.0.0",
53
+ "mongoose": "^7.0.0",
49
54
  "nodemailer": "^6.6.3",
50
55
  "nodemailer-sendmail-transport": "^1.0.2",
51
56
  "nodemailer-stub-transport": "^1.1.0",
@@ -54,20 +59,19 @@
54
59
  "redis": "^4.3.1",
55
60
  "winston": "^3.3.3",
56
61
  "winston-transport-sentry-node": "^2.0.0",
57
- "yup": "^0.32.9"
62
+ "yup": "^1.0.0"
58
63
  },
59
64
  "devDependencies": {
60
65
  "eslint": "^8.0.0",
61
66
  "eslint-config-airbnb-base": "^15.0.0",
62
67
  "eslint-config-prettier": "^8.3.0",
63
- "eslint-plugin-import": "^2.23.4",
64
68
  "eslint-plugin-jest": "^27.0.0",
65
69
  "husky": "^8.0.0",
66
70
  "jest": "^29.0.0",
67
71
  "lint-staged": "^13.0.0",
68
72
  "mongodb-memory-server": "^8.0.2",
69
- "nodemon": "^2.0.12",
70
- "prettier": "^2.3.2",
73
+ "nodemon": "^3.0.1",
74
+ "prettier": "^3.0.0",
71
75
  "supertest": "^6.1.4"
72
76
  },
73
77
  "lint-staged": {
package/server.d.ts CHANGED
@@ -19,7 +19,7 @@ declare class Server {
19
19
  getModel: Server['getModel'];
20
20
  runCliCommand: Server['runCliCommand'];
21
21
  updateConfig: Server['updateConfig'];
22
- foldersConfig: Server['config'];
22
+ foldersConfig: Server['config']['folders'];
23
23
  events: EventEmitter;
24
24
  get cache(): Server['cacheService'];
25
25
  httpServer: null;
package/server.js CHANGED
@@ -1,7 +1,8 @@
1
- /* eslint-disable global-require */
1
+ /* eslint-disable no-console */
2
+ const EventEmitter = require('node:events');
3
+
2
4
  require('dotenv').config();
3
5
  const merge = require('deepmerge');
4
- const EventEmitter = require('events');
5
6
 
6
7
  /**
7
8
  * Main framework class.
@@ -50,16 +51,27 @@ class Server {
50
51
  * @returns {Promise}
51
52
  */
52
53
  async startServer(callbackBefore404 = async () => Promise.resolve()) {
53
- const HttpServer = require('./services/http/HttpServer'); // Speed optimisation
54
- const ControllerManager = require('./controllers/index'); // Speed optimisation
54
+ // eslint-disable-next-line global-require
55
+ const HttpServer = require('./services/http/HttpServer');
56
+ // eslint-disable-next-line global-require
57
+ const ControllerManager = require('./controllers/index');
58
+ // TODO wait until https://github.com/nodejs/node/issues/35889
59
+ // const [{ default: HttpServer }, { default: ControllerManager }] =
60
+ // await Promise.all([
61
+ // // eslint-disable-next-line import/extensions
62
+ // import('./services/http/HttpServer.js'), // Speed optimisation
63
+ // // eslint-disable-next-line import/extensions
64
+ // import('./controllers/index.js'), // Speed optimisation
65
+ // ]);
66
+
55
67
  this.addErrorHandling();
56
68
 
57
69
  // TODO config
58
- this.app.httpServer = new HttpServer(this.app, this.config);
70
+ this.app.httpServer = new HttpServer(this.app);
59
71
 
60
72
  this.app.controllerManager = new ControllerManager(this.app);
61
73
 
62
- await this.app.controllerManager.initControllers(this.config);
74
+ await this.app.controllerManager.initControllers();
63
75
  await callbackBefore404();
64
76
  this.app.httpServer.add404Page();
65
77
  }
@@ -70,7 +82,7 @@ class Server {
70
82
  // eslint-disable-next-line class-methods-use-this
71
83
  addErrorHandling() {
72
84
  process.on('uncaughtException', console.error);
73
- process.on('unhandledRejection', function (reason, p) {
85
+ process.on('unhandledRejection', (reason, p) => {
74
86
  console.log(
75
87
  'Possibly Unhandled Rejection at: Promise ',
76
88
  p,
@@ -166,7 +178,11 @@ class Server {
166
178
  */
167
179
  async runCliCommand(commandName, args) {
168
180
  if (!this.cli) {
169
- const BaseCli = require('./modules/BaseCli'); // Speed optimisation
181
+ // eslint-disable-next-line import/extensions
182
+ // TODO wait until https://github.com/nodejs/node/issues/35889
183
+ // const { default: BaseCli } = await import('./modules/BaseCli.js'); // Speed optimisation
184
+ // eslint-disable-next-line global-require
185
+ const BaseCli = require('./modules/BaseCli');
170
186
  this.cli = new BaseCli(this);
171
187
  }
172
188
  return this.cli.run(commandName, args);
@@ -178,6 +194,7 @@ class Server {
178
194
  */
179
195
  getCache() {
180
196
  if (!this.cacheService) {
197
+ // eslint-disable-next-line global-require
181
198
  const Cache = require('./services/cache/Cache'); // Speed optimisation
182
199
  this.cacheService = new Cache(this.app);
183
200
  }