@adaptivestone/framework 4.6.0 → 4.8.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 (90) hide show
  1. package/CHANGELOG.md +14 -1
  2. package/Cli.js +1 -0
  3. package/cluster.js +1 -2
  4. package/commands/GetOpenApiJson.js +1 -2
  5. package/commands/SyncIndexes.js +1 -1
  6. package/commands/migration/Migrate.js +2 -2
  7. package/controllers/Auth.js +3 -5
  8. package/controllers/index.js +0 -3
  9. package/coverage/clover.xml +2035 -1926
  10. package/coverage/coverage-final.json +43 -40
  11. package/coverage/framework/config/auth.js.html +6 -6
  12. package/coverage/framework/config/http.js.html +10 -10
  13. package/coverage/framework/config/i18n.js.html +13 -13
  14. package/coverage/framework/config/index.html +1 -1
  15. package/coverage/framework/config/log.js.html +23 -23
  16. package/coverage/framework/config/mail.js.html +30 -30
  17. package/coverage/framework/config/mongo.js.html +4 -4
  18. package/coverage/framework/config/rateLimiter.js.html +17 -17
  19. package/coverage/framework/config/redis.js.html +5 -5
  20. package/coverage/framework/config/validate.js.html +4 -4
  21. package/coverage/framework/controllers/Auth.js.html +97 -103
  22. package/coverage/framework/controllers/Home.js.html +27 -27
  23. package/coverage/framework/controllers/index.html +15 -15
  24. package/coverage/framework/controllers/index.js.html +58 -67
  25. package/coverage/framework/controllers/test/SomeController.js.html +44 -89
  26. package/coverage/framework/controllers/test/index.html +17 -17
  27. package/coverage/framework/helpers/files.js.html +310 -0
  28. package/coverage/framework/helpers/index.html +131 -0
  29. package/coverage/framework/helpers/logger.js.html +142 -0
  30. package/coverage/framework/helpers/redis/clearNamespace.js.html +10 -10
  31. package/coverage/framework/helpers/redis/index.html +1 -1
  32. package/coverage/framework/index.html +19 -19
  33. package/coverage/framework/models/Migration.js.html +130 -0
  34. package/coverage/framework/models/Sequence.js.html +11 -11
  35. package/coverage/framework/models/User.js.html +130 -130
  36. package/coverage/framework/models/index.html +20 -5
  37. package/coverage/framework/modules/AbstractController.js.html +100 -106
  38. package/coverage/framework/modules/AbstractModel.js.html +58 -58
  39. package/coverage/framework/modules/Base.js.html +70 -403
  40. package/coverage/framework/modules/index.html +24 -24
  41. package/coverage/framework/server.js.html +704 -338
  42. package/coverage/framework/services/cache/Cache.js.html +96 -81
  43. package/coverage/framework/services/cache/index.html +19 -19
  44. package/coverage/framework/services/documentation/DocumentationGenerator.js.html +39 -45
  45. package/coverage/framework/services/documentation/index.html +11 -11
  46. package/coverage/framework/services/http/HttpServer.js.html +90 -90
  47. package/coverage/framework/services/http/index.html +1 -1
  48. package/coverage/framework/services/http/middleware/AbstractMiddleware.js.html +45 -45
  49. package/coverage/framework/services/http/middleware/Auth.js.html +19 -19
  50. package/coverage/framework/services/http/middleware/GetUserByToken.js.html +36 -36
  51. package/coverage/framework/services/http/middleware/I18n.js.html +67 -67
  52. package/coverage/framework/services/http/middleware/Pagination.js.html +21 -21
  53. package/coverage/framework/services/http/middleware/PrepareAppInfo.js.html +5 -5
  54. package/coverage/framework/services/http/middleware/RateLimiter.js.html +19 -19
  55. package/coverage/framework/services/http/middleware/RequestLogger.js.html +21 -21
  56. package/coverage/framework/services/http/middleware/RequestParser.js.html +7 -7
  57. package/coverage/framework/services/http/middleware/Role.js.html +43 -43
  58. package/coverage/framework/services/http/middleware/index.html +33 -33
  59. package/coverage/framework/services/http/middleware/test/CheckFlag.js.html +9 -9
  60. package/coverage/framework/services/http/middleware/test/index.html +1 -1
  61. package/coverage/framework/services/messaging/email/index.html +1 -1
  62. package/coverage/framework/services/messaging/email/index.js.html +67 -67
  63. package/coverage/framework/services/messaging/index.html +1 -1
  64. package/coverage/framework/services/messaging/index.js.html +6 -6
  65. package/coverage/framework/services/validate/ValidateService.js.html +155 -167
  66. package/coverage/framework/services/validate/drivers/AbstractValidator.js.html +24 -24
  67. package/coverage/framework/services/validate/drivers/CustomValidator.js.html +14 -14
  68. package/coverage/framework/services/validate/drivers/YupValidator.js.html +41 -41
  69. package/coverage/framework/services/validate/drivers/index.html +1 -1
  70. package/coverage/framework/services/validate/index.html +5 -5
  71. package/coverage/index.html +91 -76
  72. package/helpers/files.js +75 -0
  73. package/helpers/logger.js +19 -0
  74. package/models/Migration.test.js +19 -0
  75. package/modules/AbstractController.js +2 -4
  76. package/modules/Base.js +8 -119
  77. package/modules/BaseCli.js +0 -4
  78. package/package.json +2 -2
  79. package/server.d.ts +14 -1
  80. package/server.js +208 -86
  81. package/services/cache/Cache.js +10 -5
  82. package/services/cache/Cache.test.js +81 -0
  83. package/services/documentation/DocumentationGenerator.js +18 -20
  84. package/services/http/middleware/Auth.test.js +57 -0
  85. package/services/http/middleware/I18n.test.js +15 -3
  86. package/services/http/middleware/PrepareAppInfo.test.js +1 -1
  87. package/services/http/middleware/Role.test.js +93 -0
  88. package/services/validate/ValidateService.js +3 -7
  89. package/tests/setup.js +1 -0
  90. package/tests/setupVitest.js +1 -0
package/modules/Base.js CHANGED
@@ -1,5 +1,4 @@
1
- const fs = require('node:fs').promises;
2
- const { join, normalize } = require('node:path');
1
+ const { getFilesPathWithInheritance } = require('../helpers/files');
3
2
 
4
3
  class Base {
5
4
  #realLogger = null;
@@ -29,128 +28,18 @@ class Base {
29
28
 
30
29
  /**
31
30
  * Get winston loger for given label
32
- * @param {sting} label name of logger
31
+ * @param {string} label name of logger
33
32
  */
34
33
  getLogger(label) {
35
- // eslint-disable-next-line global-require
36
- const winston = require('winston'); // speed up optimisation
37
- const alignColorsAndTime = winston.format.combine(
38
- winston.format.colorize({
39
- all: true,
40
- }),
41
- winston.format.label({
42
- label: ` \x1B[32m[${label}]\x1B[39m`,
43
- }),
44
- winston.format.timestamp(),
45
- winston.format.printf(
46
- (info) =>
47
- `(${process.pid}) ${info.label} ${info.timestamp} ${info.level} : ${info.message}`,
48
- ),
49
- );
50
-
51
- const logConfig = this.app.getConfig('log').transports;
52
-
53
- function IsConstructor(f) {
54
- try {
55
- Reflect.construct(String, [], f);
56
- } catch (e) {
57
- return false;
58
- }
59
- return true;
60
- }
61
- const transports = [];
62
- for (const log of logConfig) {
63
- if (log.enable) {
64
- if (log.transport === 'console') {
65
- transports.push(
66
- new winston.transports.Console({
67
- level: log.transportOptions.level,
68
- format: winston.format.combine(
69
- winston.format.colorize(),
70
- alignColorsAndTime,
71
- ),
72
- }),
73
- );
74
- } else {
75
- // eslint-disable-next-line global-require, import/no-dynamic-require
76
- let Tr = require(log.transport);
77
- if (!IsConstructor(Tr) && Tr.default) {
78
- Tr = Tr.default;
79
- } else {
80
- // eslint-disable-next-line no-console
81
- console.error(
82
- `${log.transport} not a constructor. Please check it`,
83
- );
84
- // eslint-disable-next-line no-continue
85
- continue;
86
- }
87
-
88
- transports.push(new Tr(log.transportOptions));
89
- }
90
- }
91
- }
92
-
93
- return winston.createLogger({
94
- level: 'silly',
95
- transports,
96
- });
34
+ return this.app.logger.child({ label });
97
35
  }
98
36
 
99
37
  async getFilesPathWithInheritance(internalFolder, externalFolder) {
100
- async function rreaddir(dir, allFiles = []) {
101
- const files = (await fs.readdir(dir)).map((f) => join(dir, f));
102
- allFiles.push(...files);
103
- await Promise.all(
104
- files.map(async (f) => {
105
- if ((await fs.stat(f)).isDirectory()) {
106
- allFiles.pop();
107
- return rreaddir(f, allFiles);
108
- }
109
- return null;
110
- }),
111
- );
112
- return allFiles.map((file) => file.replace(`${normalize(dir)}/`, ''));
113
- }
114
-
115
- let [internalFiles, externalFiles] = await Promise.all([
116
- rreaddir(internalFolder),
117
- rreaddir(externalFolder),
118
- ]);
119
-
120
- const filterIndexFile = (fileName) => {
121
- const fileArray = fileName.split('/');
122
- const file = fileArray[fileArray.length - 1];
123
- return (
124
- file[0] === file[0].toUpperCase() && // Start with capital
125
- file[0] !== '.' && // not start with dot
126
- !file.includes('.test.js') // not test files
127
- );
128
- };
129
-
130
- internalFiles = internalFiles.filter(filterIndexFile);
131
- externalFiles = externalFiles.filter(filterIndexFile);
132
-
133
- const filesToLoad = [];
134
- for (const file of internalFiles) {
135
- if (externalFiles.includes(file)) {
136
- this.logger.verbose(
137
- `Skipping register INTERNAL file ${file} as it override by EXTERNAL ONE`,
138
- );
139
- } else {
140
- filesToLoad.push({
141
- path: `${internalFolder}/${file}`,
142
- file,
143
- });
144
- }
145
- }
146
-
147
- for (const file of externalFiles) {
148
- filesToLoad.push({
149
- path: `${externalFolder}/${file}`,
150
- file,
151
- });
152
- }
153
- return filesToLoad;
38
+ return getFilesPathWithInheritance({
39
+ internalFolder,
40
+ externalFolder,
41
+ logger: (text) => this.logger.verbose(text),
42
+ });
154
43
  }
155
44
 
156
45
  /**
@@ -47,12 +47,8 @@ class Cli extends Base {
47
47
  );
48
48
  return false;
49
49
  }
50
- // TODO wait until https://github.com/nodejs/node/issues/35889
51
50
  const { default: Command } = await import(this.commands[command]);
52
51
 
53
- // eslint-disable-next-line import/no-dynamic-require, global-require
54
- // const Command = require(this.commands[command]);
55
-
56
52
  const c = new Command(this.app, this.commands, args);
57
53
  let result = false;
58
54
 
package/package.json CHANGED
@@ -1,10 +1,10 @@
1
1
  {
2
2
  "name": "@adaptivestone/framework",
3
- "version": "4.6.0",
3
+ "version": "4.8.0",
4
4
  "description": "Adaptive stone node js framework",
5
5
  "main": "index.js",
6
6
  "engines": {
7
- "node": ">=18.0.0"
7
+ "node": ">=18.17.0"
8
8
  },
9
9
  "repository": {
10
10
  "type": "git",
package/server.d.ts CHANGED
@@ -7,6 +7,7 @@ import { Model as MongooseModel, Schema } from 'mongoose';
7
7
 
8
8
  import BaseCli from './modules/BaseCli';
9
9
  import Cache from './services/cache/Cache';
10
+ import winston from 'winston';
10
11
 
11
12
  type ServerConfig = {
12
13
  folders: ExpandDeep<TFolderConfig>;
@@ -22,6 +23,7 @@ declare class Server {
22
23
  foldersConfig: Server['config']['folders'];
23
24
  events: EventEmitter;
24
25
  get cache(): Server['cacheService'];
26
+ get logger(): winston.Logger;
25
27
  httpServer: null;
26
28
  controllerManager: null;
27
29
  };
@@ -39,10 +41,16 @@ declare class Server {
39
41
  constructor(config: ExpandDeep<ServerConfig>);
40
42
 
41
43
  /**
42
- * Start server (http + websocket + init all http and websocet ralated functions)
44
+ * Start server (http + init all http ralated functions)
43
45
  */
44
46
  startServer(callbackBefore404?: Promise<null>): Promise<null>;
45
47
 
48
+ /**
49
+ * Do an initialization (config reading, etc)
50
+ * @returns {Promise}
51
+ */
52
+ init(): Promise<boolean>;
53
+
46
54
  /**
47
55
  * Return config from {configName} (file name) on config folder.
48
56
  * Support cache and updating confing into cache
@@ -54,6 +62,11 @@ declare class Server {
54
62
  */
55
63
  getConfig(configName: string): {};
56
64
 
65
+ /**
66
+ * Return or create new logger instance. This is a main logger instance
67
+ */
68
+ getLogger(): winston.Logger;
69
+
57
70
  /**
58
71
  * Primary designed for tests when we need to update some configs before start testing
59
72
  * Should be called before any initialization was done
package/server.js CHANGED
@@ -1,13 +1,23 @@
1
1
  /* eslint-disable no-console */
2
2
  const EventEmitter = require('node:events');
3
+ const { hrtime } = require('node:process');
3
4
 
4
5
  require('dotenv').config();
5
6
  const merge = require('deepmerge');
7
+ const winston = require('winston');
8
+ const { getFilesPathWithInheritance } = require('./helpers/files');
9
+ const { consoleLogger } = require('./helpers/logger');
10
+
11
+ const Cache = require('./services/cache/Cache');
6
12
 
7
13
  /**
8
14
  * Main framework class.
9
15
  */
10
16
  class Server {
17
+ #realLogger = null;
18
+
19
+ #isInited = false;
20
+
11
21
  /**
12
22
  * Construct new server
13
23
  * @param {Object} config main config object
@@ -33,6 +43,9 @@ class Server {
33
43
  get cache() {
34
44
  return that.getCache();
35
45
  },
46
+ get logger() {
47
+ return that.getLogger();
48
+ },
36
49
  httpServer: null,
37
50
  controllerManager: null,
38
51
  };
@@ -40,28 +53,23 @@ class Server {
40
53
  this.cache = {
41
54
  configs: new Map(),
42
55
  models: new Map(),
56
+ modelConstructors: new Map(),
43
57
  };
44
58
 
45
59
  this.cli = false;
46
60
  }
47
61
 
48
62
  /**
49
- * Start server (http + websocket + init all http and websocet ralated functions)
63
+ * Start server (http + init all http ralated functions)
50
64
  * @param <Promise>callbackBefore404 code that should be executed before adding page 404
51
65
  * @returns {Promise}
52
66
  */
53
67
  async startServer(callbackBefore404 = async () => Promise.resolve()) {
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
68
  const [{ default: HttpServer }, { default: ControllerManager }] =
60
69
  await Promise.all([
61
- // eslint-disable-next-line import/extensions
62
70
  import('./services/http/HttpServer.js'), // Speed optimisation
63
- // eslint-disable-next-line import/extensions
64
71
  import('./controllers/index.js'), // Speed optimisation
72
+ this.init(),
65
73
  ]);
66
74
 
67
75
  this.addErrorHandling();
@@ -76,20 +84,115 @@ class Server {
76
84
  this.app.httpServer.add404Page();
77
85
  }
78
86
 
87
+ /**
88
+ * Do an initialization (config reading, etc)
89
+ * @returns {Promise}
90
+ */
91
+ async init() {
92
+ if (this.#isInited) {
93
+ return true;
94
+ }
95
+
96
+ console.time('Server init. Done');
97
+ await Promise.all([this.#initConfigFiles(), this.#loadModelFiles()]);
98
+
99
+ this.#isInited = true;
100
+
101
+ console.timeEnd('Server init. Done');
102
+
103
+ return true;
104
+ }
105
+
106
+ async #initConfigFiles() {
107
+ const files = await getFilesPathWithInheritance({
108
+ internalFolder: `${__dirname}/config`,
109
+ externalFolder: this.app.foldersConfig.config,
110
+ loggerFileType: 'CONFIG',
111
+ logger: (m) => consoleLogger('info', m),
112
+ filter: {
113
+ startWithCapital: false,
114
+ },
115
+ });
116
+
117
+ const configFiles = {};
118
+
119
+ for (const file of files) {
120
+ const config = file.file.split('.');
121
+ if (!configFiles[config[0]]) {
122
+ configFiles[config[0]] = {};
123
+ }
124
+ if (config.length === 2) {
125
+ configFiles[config[0]].default = file.path;
126
+ } else {
127
+ configFiles[config[0]][config[1]] = file.path;
128
+ }
129
+ }
130
+
131
+ const loadConfig = async (configName, values) => {
132
+ const promises = [import(values.default)];
133
+ if (process.env.NODE_ENV && values[process.env.NODE_ENV]) {
134
+ promises.push(import(values[process.env.NODE_ENV]));
135
+ }
136
+ const result = await Promise.all(promises);
137
+ return {
138
+ name: configName,
139
+ finalValue: merge(result[0].default, result[1]?.default || {}, {
140
+ arrayMerge: (destinationArray, sourceArray) => sourceArray,
141
+ }),
142
+ };
143
+ };
144
+
145
+ const loadingPromises = [];
146
+
147
+ for (const [configFile, value] of Object.entries(configFiles)) {
148
+ loadingPromises.push(loadConfig(configFile, value));
149
+ }
150
+
151
+ const configs = await Promise.all(loadingPromises);
152
+
153
+ for (const config of configs) {
154
+ this.cache.configs.set(config.name, config.finalValue);
155
+ }
156
+ return true;
157
+ }
158
+
159
+ async #loadModelFiles() {
160
+ const files = await getFilesPathWithInheritance({
161
+ internalFolder: `${__dirname}/models`,
162
+ externalFolder: this.app.foldersConfig.models,
163
+ loggerFileType: 'MODEL',
164
+ logger: (m) => consoleLogger('info', m),
165
+ });
166
+
167
+ const promises = [];
168
+ for (const file of files) {
169
+ const t = hrtime.bigint();
170
+ promises.push(
171
+ import(file.path).then((f) => ({
172
+ name: file.file.split('.')[0],
173
+ file: f,
174
+ took: hrtime.bigint() - t,
175
+ })),
176
+ );
177
+ }
178
+
179
+ const loadedModels = await Promise.all(promises);
180
+
181
+ for (const model of loadedModels) {
182
+ this.cache.modelConstructors.set(model.name, model.file.default);
183
+ }
184
+ return true;
185
+ }
186
+
79
187
  /**
80
188
  * Add error logging on promise reject
81
189
  */
82
- // eslint-disable-next-line class-methods-use-this
83
190
  addErrorHandling() {
84
- process.on('uncaughtException', console.error);
85
- process.on('unhandledRejection', (reason, p) => {
86
- console.log(
87
- 'Possibly Unhandled Rejection at: Promise ',
88
- p,
89
- ' reason: ',
90
- reason,
91
- );
92
- console.trace('unhandledRejection');
191
+ process.on('uncaughtException', (e) =>
192
+ this.app.logger.error('uncaughtException', e),
193
+ );
194
+ process.on('unhandledRejection', (e) => {
195
+ this.app.logger.error('unhandledRejection', e);
93
196
  });
94
197
  }
95
198
 
@@ -104,28 +207,93 @@ class Server {
104
207
  * @returns {Object} config object. Structure depends of config file
105
208
  */
106
209
  getConfig(configName) {
107
- // const configName = name.charAt(0).toUpperCase() + name.slice(1);
210
+ if (!this.#isInited) {
211
+ throw new Error('You should call Server.init() before using it');
212
+ }
213
+
108
214
  if (!this.cache.configs.has(configName)) {
109
- let envConfig = {};
110
- if (process.env.NODE_ENV) {
111
- envConfig =
112
- this.getFileWithExtendingInhirence(
113
- 'config',
114
- `${configName}.${process.env.NODE_ENV}.js`,
115
- ) || envConfig;
116
- }
117
- this.cache.configs.set(
118
- configName,
119
- merge(
120
- this.getFileWithExtendingInhirence('config', configName),
121
- envConfig,
122
- { arrayMerge: (destinationArray, sourceArray) => sourceArray },
123
- ),
215
+ this.logger.warn(
216
+ `You asked for config ${configName} that not exists. Please check you codebase `,
124
217
  );
218
+ return {};
125
219
  }
126
220
  return this.cache.configs.get(configName);
127
221
  }
128
222
 
223
+ /**
224
+ * Return or create new logger instance. This is a main logger instance
225
+ */
226
+ getLogger() {
227
+ if (!this.#realLogger) {
228
+ this.#realLogger = this.#createLogger();
229
+ }
230
+ return this.#realLogger;
231
+ }
232
+
233
+ #createLogger() {
234
+ const alignColorsAndTime = winston.format.combine(
235
+ winston.format.colorize({
236
+ all: true,
237
+ }),
238
+ winston.format.timestamp(),
239
+ winston.format.printf(
240
+ (info) =>
241
+ `(${process.pid}) \x1B[32m[${info.label ?? 'SERVER'}]\x1B[39m ${
242
+ info.timestamp
243
+ } ${info.level} : ${info.message} ${info?.stack ?? ''} ${
244
+ info.durationMs ? `Duration: ${info.durationMs}ms` : ''
245
+ }`,
246
+ ),
247
+ );
248
+ const logConfig = this.app.getConfig('log').transports;
249
+ function IsConstructor(f) {
250
+ try {
251
+ Reflect.construct(String, [], f);
252
+ } catch (e) {
253
+ return false;
254
+ }
255
+ return true;
256
+ }
257
+
258
+ const logger = winston.createLogger({
259
+ format: winston.format.errors({ stack: true }),
260
+ level: 'silly',
261
+ });
262
+
263
+ for (const log of logConfig) {
264
+ if (log.enable) {
265
+ if (log.transport === 'console') {
266
+ logger.add(
267
+ new winston.transports.Console({
268
+ level: log.transportOptions.level,
269
+ format: winston.format.combine(
270
+ winston.format.colorize(),
271
+ alignColorsAndTime,
272
+ ),
273
+ }),
274
+ );
275
+ } else {
276
+ import(log.transport).then((Tr) => {
277
+ let Transport = Tr.default;
278
+ if (!IsConstructor(Transport) && Transport.default) {
279
+ Transport = Transport.default;
280
+ } else {
281
+ console.error(
282
+ `${log.transport} not a constructor. Please check it`,
283
+ );
284
+ return;
285
+ }
286
+ logger.profile(`Adding new logger ${log.transport}`);
287
+ logger.add(new Transport(log.transportOptions));
288
+ logger.profile(`Adding new logger ${log.transport}`);
289
+ });
290
+ }
291
+ }
292
+ }
293
+
294
+ return logger;
295
+ }
296
+
129
297
  /**
130
298
  * Primary designed for tests when we need to update some configs before start testing
131
299
  * Should be called before any initialization was done
@@ -149,14 +317,14 @@ class Server {
149
317
  */
150
318
  getModel(modelName) {
151
319
  if (modelName.endsWith('s')) {
152
- console.warn(
320
+ this.app.logger.warn(
153
321
  `Probably your model name '${modelName}' in plural from. Try to avoid plural form`,
154
322
  );
155
323
  }
156
324
  if (!this.cache.models.has(modelName)) {
157
- const Model = this.getFileWithExtendingInhirence('models', modelName);
325
+ const Model = this.cache.modelConstructors.get(modelName);
158
326
  if (!Model) {
159
- console.error(`Model not found: ${modelName}`);
327
+ this.app.logger.error(`Model not found: ${modelName}`);
160
328
  return false;
161
329
  }
162
330
  try {
@@ -164,8 +332,8 @@ class Server {
164
332
 
165
333
  this.cache.models.set(modelName, model.mongooseModel);
166
334
  } catch (e) {
167
- console.error(`Problem with model ${modelName}, ${e.message}`);
168
- console.error(e);
335
+ this.app.logger.error(`Problem with model ${modelName}, ${e.message}`);
336
+ this.app.logger.error(e);
169
337
  }
170
338
  }
171
339
  return this.cache.models.get(modelName);
@@ -178,11 +346,7 @@ class Server {
178
346
  */
179
347
  async runCliCommand(commandName, args) {
180
348
  if (!this.cli) {
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');
349
+ const { default: BaseCli } = await import('./modules/BaseCli.js'); // Speed optimisation
186
350
  this.cli = new BaseCli(this);
187
351
  }
188
352
  return this.cli.run(commandName, args);
@@ -194,52 +358,10 @@ class Server {
194
358
  */
195
359
  getCache() {
196
360
  if (!this.cacheService) {
197
- // eslint-disable-next-line global-require
198
- const Cache = require('./services/cache/Cache'); // Speed optimisation
199
361
  this.cacheService = new Cache(this.app);
200
362
  }
201
363
  return this.cacheService;
202
364
  }
203
-
204
- /**
205
- * Get file using Inhirence (ability to overrite models, configs, etc)
206
- * @param {('models'|'config')} fileType type of file to load
207
- * @param {string} fileName name of file to load
208
- */
209
- getFileWithExtendingInhirence(fileType, fileName) {
210
- let file;
211
- try {
212
- // eslint-disable-next-line global-require, import/no-dynamic-require
213
- file = require(`${this.config.folders[fileType]}/${fileName}`);
214
- } catch (e) {
215
- try {
216
- // eslint-disable-next-line global-require, import/no-dynamic-require
217
- file = require(`./${fileType}/${fileName}`);
218
- } catch (e2) {
219
- const levels = [
220
- 'error',
221
- 'warn',
222
- 'info',
223
- 'http',
224
- 'verbose',
225
- 'debug',
226
- 'silly',
227
- ];
228
-
229
- if (
230
- !process.env.LOGGER_CONSOLE_LEVEL ||
231
- levels.indexOf(process.env.LOGGER_CONSOLE_LEVEL) > 0 // as a warn level
232
- ) {
233
- console.warn(
234
- `Config not found '${fileName}'. This can be a normal (in case this an environment config)`,
235
- );
236
- }
237
-
238
- file = false;
239
- }
240
- }
241
- return file;
242
- }
243
365
  }
244
366
 
245
367
  module.exports = Server;
@@ -1,13 +1,17 @@
1
- const redis = require('redis');
2
1
  const Base = require('../../modules/Base');
3
2
 
4
3
  class Cache extends Base {
5
4
  constructor(app) {
5
+ super(app);
6
+ this.whenReady = this.#init();
7
+ }
8
+
9
+ async #init() {
6
10
  // todo for now only redis. refactor for drives support in future
7
11
  // at least memory and redis drivers should be presented
8
12
  // memory drives should works on master process level
9
13
  // we should support multiple cashe same time
10
- super(app);
14
+ const redis = await import('redis');
11
15
  const conf = this.app.getConfig('redis');
12
16
  this.redisClient = redis.createClient({
13
17
  url: conf.url,
@@ -33,6 +37,7 @@ class Cache extends Base {
33
37
  }
34
38
 
35
39
  async getSetValue(keyValue, onNotFound, storeTime = 60 * 5) {
40
+ await this.whenReady;
36
41
  if (!this.redisClient.isOpen) {
37
42
  await this.redisClient.connect();
38
43
  }
@@ -58,9 +63,7 @@ class Cache extends Base {
58
63
  try {
59
64
  result = await onNotFound();
60
65
  } catch (e) {
61
- this.logger.error(
62
- `Cache onNotFound for key '${key}' error: ${e.message}`,
63
- );
66
+ this.logger.error(`Cache onNotFound for key '${key}' error: ${e}`);
64
67
  this.promiseMapping.delete(key);
65
68
  reject(e);
66
69
  return Promise.reject(e);
@@ -100,6 +103,8 @@ class Cache extends Base {
100
103
  }
101
104
 
102
105
  async removeKey(keyValue) {
106
+ await this.whenReady;
107
+
103
108
  if (!this.redisClient.isOpen) {
104
109
  await this.redisClient.connect();
105
110
  }