@adaptivestone/framework 5.0.0-alpha.9 → 5.0.0-beta.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 (48) hide show
  1. package/CHANGELOG.md +84 -0
  2. package/commands/CreateUser.js +4 -0
  3. package/commands/Documentation.js +4 -0
  4. package/commands/GenerateRandomBytes.js +19 -0
  5. package/commands/GetOpenApiJson.js +4 -0
  6. package/config/auth.js +4 -1
  7. package/config/ipDetector.js +14 -0
  8. package/controllers/Auth.js +2 -2
  9. package/controllers/Home.js +1 -1
  10. package/helpers/files.js +8 -8
  11. package/models/User.js +7 -1
  12. package/modules/AbstractCommand.js +1 -1
  13. package/modules/AbstractController.js +19 -19
  14. package/modules/AbstractModel.d.ts +48 -0
  15. package/modules/AbstractModel.js +16 -1
  16. package/modules/Base.d.ts +4 -4
  17. package/modules/Base.js +11 -1
  18. package/modules/BaseCli.js +23 -8
  19. package/package.json +10 -11
  20. package/server.js +1 -1
  21. package/services/cache/Cache.js +6 -4
  22. package/services/http/HttpServer.js +11 -9
  23. package/services/http/middleware/GetUserByToken.js +3 -2
  24. package/services/http/middleware/I18n.js +21 -22
  25. package/services/http/middleware/IpDetector.js +59 -0
  26. package/services/http/middleware/Pagination.js +3 -2
  27. package/services/http/middleware/RateLimiter.js +8 -2
  28. package/services/http/middleware/RequestLogger.js +3 -3
  29. package/services/http/middleware/RequestParser.js +1 -1
  30. package/services/validate/ValidateService.js +1 -1
  31. package/.eslintrc.cjs +0 -41
  32. package/commands/Generate.js +0 -14
  33. package/controllers/Auth.test.js +0 -451
  34. package/controllers/Home.test.js +0 -12
  35. package/models/Migration.test.js +0 -20
  36. package/models/Sequence.test.js +0 -43
  37. package/models/User.test.js +0 -143
  38. package/modules/Modules.test.js +0 -18
  39. package/services/cache/Cache.test.js +0 -81
  40. package/services/http/middleware/Auth.test.js +0 -57
  41. package/services/http/middleware/Cors.test.js +0 -147
  42. package/services/http/middleware/GetUserByToken.test.js +0 -108
  43. package/services/http/middleware/I18n.test.js +0 -96
  44. package/services/http/middleware/PrepareAppInfo.test.js +0 -26
  45. package/services/http/middleware/RateLimiter.test.js +0 -233
  46. package/services/http/middleware/RequestParser.test.js +0 -121
  47. package/services/http/middleware/Role.test.js +0 -93
  48. package/services/validate/ValidateService.test.js +0 -107
package/CHANGELOG.md CHANGED
@@ -1,3 +1,87 @@
1
+ ### 5.0.0-beta.1
2
+
3
+ [UPDATE] update deps
4
+ [BREAKING] vitest v3 https://vitest.dev/guide/migration.html
5
+
6
+ ### 5.0.0-alpha.26
7
+
8
+ [UPDATE] update deps
9
+ [UPDATE] new commands view in CLI
10
+
11
+ ### 5.0.0-alpha.24
12
+
13
+ [UPDATE] update deps
14
+ [BREAKING] i18next v24 https://www.i18next.com/misc/migration-guide#v23.x.x-to-v24.0.0
15
+
16
+ ### 5.0.0-alpha.23
17
+
18
+ [UPDATE] update deps
19
+
20
+ ### 5.0.0-alpha.22
21
+
22
+ [UPDATE] update deps
23
+ [FIX] fix optional routing parameters
24
+
25
+ ### 5.0.0-alpha.21
26
+
27
+ [BREAKING] possible breaking. Framework start using express 5 instead of express 4. Please follow express migration guide too https://expressjs.com/en/guide/migrating-5.html.
28
+ [BREAKING] AS part of express 5 migration _ in rotes (middlewares) should have perameter. please replace _ to \*splat
29
+ [UPDATE] update deps
30
+ [UPDATE] Mailer uses await import() for startup speedup
31
+
32
+ ### 5.0.0-alpha.20
33
+
34
+ [UPDATE] update deps
35
+ [UPDATE] #realLogger do not throw error in a scecific cases (model toJSON({virtual:true}))
36
+
37
+ ### 5.0.0-alpha.19
38
+
39
+ [NEW] added modelSchemaOptions for models
40
+
41
+ ### 5.0.0-alpha.18
42
+
43
+ [BREAKING] default auth responce changed to be unified. {token, user} = > {data:{token, user}}
44
+ [UPDATE] RateLimiter updae key generation
45
+
46
+ ### 5.0.0-alpha.17
47
+
48
+ [NEW] generateRandomBytes command
49
+ [UPDATE] update deps
50
+
51
+ ### 5.0.0-alpha.16
52
+
53
+ [UPDATE] no warning of direct usage body and query
54
+ [UPDATE] update deps
55
+
56
+ ### 5.0.0-alpha.15
57
+
58
+ [BUG] fix bug with pagination
59
+ [UPDATE] update deps
60
+
61
+ ### 5.0.0-alpha.14
62
+
63
+ [NEW] add types for Abstract model (wip)
64
+
65
+ ### 5.0.0-alpha.13
66
+
67
+ [UPDATE] update deps
68
+ [UPDATE] update i18n internal implementation
69
+ [CHANGE] disable https server view
70
+
71
+ ### 5.0.0-alpha.12
72
+
73
+ [UPDATE] update deps
74
+
75
+ ### 5.0.0-alpha.11
76
+
77
+ [UPDATE] update deps
78
+
79
+ ### 5.0.0-alpha.10
80
+
81
+ [UPDATE] update deps
82
+ [NEW] IpDetector middleware that support detecting proxy and X-Forwarded-For header
83
+ [BREAKING] RateLimiter now need to have IpDetector middleware before
84
+
1
85
  ### 5.0.0-alpha.9
2
86
 
3
87
  [UPDATE] update deps
@@ -2,6 +2,10 @@ import AbstractCommand from '../modules/AbstractCommand.js';
2
2
 
3
3
  // Example: node src/cli createuser --email=somemail@gmail.com --password=somePassword --roles=user,admin,someOtherRoles
4
4
  class CreateUser extends AbstractCommand {
5
+ static get description() {
6
+ return 'Create user in a database';
7
+ }
8
+
5
9
  async run() {
6
10
  const User = this.app.getModel('User');
7
11
  const { id, email, password, roles, update } = this.args;
@@ -2,6 +2,10 @@ import AbstractCommand from '../modules/AbstractCommand.js';
2
2
  import ControllerManager from '../controllers/index.js';
3
3
 
4
4
  class Documentation extends AbstractCommand {
5
+ static get description() {
6
+ return 'Generate documentation (internal)';
7
+ }
8
+
5
9
  async run() {
6
10
  const CM = new ControllerManager(this.app);
7
11
  this.app.documentation = [];
@@ -0,0 +1,19 @@
1
+ import { randomBytes } from 'node:crypto';
2
+ import AbstractCommand from '../modules/AbstractCommand.js';
3
+
4
+ class GenerateRandomBytes extends AbstractCommand {
5
+ static get description() {
6
+ return 'Generate random bytes ising randomBytes from node:crypto';
7
+ }
8
+
9
+ async run() {
10
+ const sizes = [16, 32, 64, 128, 256];
11
+ for (const size of sizes) {
12
+ const bytes = randomBytes(size).toString('hex');
13
+ this.logger.info(`${size} bytes: ${bytes}`);
14
+ }
15
+ return true;
16
+ }
17
+ }
18
+
19
+ export default GenerateRandomBytes;
@@ -5,6 +5,10 @@ import AbstractCommand from '../modules/AbstractCommand.js';
5
5
  * Command for generate documentation json file openApi
6
6
  */
7
7
  class GetOpenApiJson extends AbstractCommand {
8
+ static get description() {
9
+ return 'Generate documentation (openApi) ';
10
+ }
11
+
8
12
  async run() {
9
13
  const { myDomain } = this.app.getConfig('http');
10
14
  let jsonFile = process.env.npm_package_json;
package/config/auth.js CHANGED
@@ -1,6 +1,9 @@
1
1
  export default {
2
2
  hashRounds: 64,
3
3
  saltSecret:
4
- process.env.AUTH_SALT || console.error('AUTH_SALT is not defined'),
4
+ process.env.AUTH_SALT ||
5
+ console.error(
6
+ 'AUTH_SALT is not defined. You can "npm run cli generateRandomBytes" and use it',
7
+ ),
5
8
  isAuthWithVefificationFlow: true,
6
9
  };
@@ -0,0 +1,14 @@
1
+ export default {
2
+ headers: ['X-Forwarded-For'],
3
+ trustedProxy: [
4
+ // list of trusted proxies.
5
+ '169.254.0.0/16', // linklocal
6
+ 'fe80::/10', // linklocal
7
+ '127.0.0.1/8', // loopback
8
+ '::1/128', // loopback
9
+ '10.0.0.0/8', // uniquelocal
10
+ '172.16.0.0/12', // uniquelocal
11
+ '192.168.0.0/16', // uniquelocal
12
+ 'fc00::/7', // uniquelocal
13
+ ],
14
+ };
@@ -83,7 +83,7 @@ class Auth extends AbstractController {
83
83
  }
84
84
  const token = await user.generateToken();
85
85
 
86
- return res.status(200).json({ token, user: user.getPublic() });
86
+ return res.status(200).json({ data: { token, user: user.getPublic() } });
87
87
  }
88
88
 
89
89
  async postRegister(req, res) {
@@ -203,7 +203,7 @@ class Auth extends AbstractController {
203
203
  }
204
204
 
205
205
  static get middleware() {
206
- return new Map([['/*', [GetUserByToken, RateLimiter]]]);
206
+ return new Map([['/{*splat}', [GetUserByToken, RateLimiter]]]);
207
207
  }
208
208
  }
209
209
 
@@ -21,7 +21,7 @@ class Home extends AbstractController {
21
21
  }
22
22
 
23
23
  static get middleware() {
24
- return new Map([['/*', [GetUserByToken]]]);
24
+ return new Map([['/{*splat}', [GetUserByToken]]]);
25
25
  }
26
26
  }
27
27
 
package/helpers/files.js CHANGED
@@ -8,7 +8,7 @@ const getFilesPathWithInheritance = async ({
8
8
  loggerFileType = '',
9
9
  filter: { startWithCapital = true, notTests = true, notHidden = true } = {},
10
10
  }) => {
11
- let [internalFiles, externalFiles] = await Promise.all([
11
+ const [internalFiles, externalFiles] = await Promise.all([
12
12
  fs.readdir(internalFolder, { recursive: true, withFileTypes: true }),
13
13
  fs.readdir(externalFolder, { recursive: true, withFileTypes: true }),
14
14
  ]);
@@ -33,24 +33,24 @@ const getFilesPathWithInheritance = async ({
33
33
  return true;
34
34
  };
35
35
 
36
- internalFiles = internalFiles
36
+ const internalFilesString = internalFiles
37
37
  .filter(filterIndexFile)
38
38
  .map((fileDirent) =>
39
- join(fileDirent.path, fileDirent.name)
39
+ join(fileDirent.parentPath, fileDirent.name)
40
40
  .replace(`${internalFolder}/`, '')
41
41
  .replace(`${internalFolder}`, ''),
42
42
  );
43
- externalFiles = externalFiles
43
+ const externalFilesString = externalFiles
44
44
  .filter(filterIndexFile)
45
45
  .map((fileDirent) =>
46
- join(fileDirent.path, fileDirent.name)
46
+ join(fileDirent.parentPath, fileDirent.name)
47
47
  .replace(`${externalFolder}/`, '')
48
48
  .replace(`${externalFolder}`, ''),
49
49
  );
50
50
 
51
51
  const filesToLoad = [];
52
- for (const file of internalFiles) {
53
- if (externalFiles.includes(file)) {
52
+ for (const file of internalFilesString) {
53
+ if (externalFilesString.includes(file)) {
54
54
  logger(
55
55
  `Skipping register INTERNAL file '${file}' ${
56
56
  loggerFileType ? `of type ${loggerFileType}` : ''
@@ -64,7 +64,7 @@ const getFilesPathWithInheritance = async ({
64
64
  }
65
65
  }
66
66
 
67
- for (const file of externalFiles) {
67
+ for (const file of externalFilesString) {
68
68
  filesToLoad.push({
69
69
  path: join(externalFolder, file),
70
70
  file,
package/models/User.js CHANGED
@@ -4,7 +4,6 @@ import { scrypt } from 'node:crypto';
4
4
 
5
5
  import { promisify } from 'node:util';
6
6
  import AbstractModel from '../modules/AbstractModel.js';
7
- import Mailer from '../services/messaging/email/index.js';
8
7
 
9
8
  class User extends AbstractModel {
10
9
  constructor(app) {
@@ -175,6 +174,10 @@ class User extends AbstractModel {
175
174
  async sendPasswordRecoveryEmail(i18n) {
176
175
  const passwordRecoveryToken =
177
176
  await User.generateUserPasswordRecoveryToken(this);
177
+ // speed optimisation
178
+ const Mailer = (await import('../services/messaging/email/index.js'))
179
+ .default;
180
+
178
181
  const mail = new Mailer(
179
182
  this.getSuper().app,
180
183
  'recovery',
@@ -241,6 +244,9 @@ class User extends AbstractModel {
241
244
 
242
245
  async sendVerificationEmail(i18n) {
243
246
  const verificationToken = await User.generateUserVerificationToken(this);
247
+ // speed optimisation
248
+ const Mailer = (await import('../services/messaging/email/index.js'))
249
+ .default;
244
250
  const mail = new Mailer(
245
251
  this.getSuper().app,
246
252
  'verification',
@@ -8,7 +8,7 @@ class AbstractCommand extends Base {
8
8
  }
9
9
 
10
10
  static get description() {
11
- return 'Command description';
11
+ return 'Command description. PLEASE PROVIDE IT';
12
12
  }
13
13
 
14
14
  /**
@@ -196,22 +196,22 @@ class AbstractController extends Base {
196
196
  errors: err.message,
197
197
  });
198
198
  }
199
- req.body = new Proxy(req.body, {
200
- get: (target, prop) => {
201
- this.logger.warn(
202
- 'Please not use "req.body" directly. Implement "request" and use "req.appInfo.request" ',
203
- );
204
- return target[prop];
205
- },
206
- });
207
- req.query = new Proxy(req.query, {
208
- get: (target, prop) => {
209
- this.logger.warn(
210
- 'Please not use "req.query" directly. Implement "query" and use "req.appInfo.query" ',
211
- );
212
- return target[prop];
213
- },
214
- });
199
+ // req.body = new Proxy(req.body, {
200
+ // get: (target, prop) => {
201
+ // this.logger.warn(
202
+ // 'Please not use "req.body" directly. Implement "request" and use "req.appInfo.request" ',
203
+ // );
204
+ // return target[prop];
205
+ // },
206
+ // });
207
+ // req.query = new Proxy(req.query, {
208
+ // get: (target, prop) => {
209
+ // this.logger.warn(
210
+ // 'Please not use "req.query" directly. Implement "query" and use "req.appInfo.query" ',
211
+ // );
212
+ // return target[prop];
213
+ // },
214
+ // });
215
215
 
216
216
  if (!routeObject.handler) {
217
217
  this.logger.error(`Route object have no handler defined`);
@@ -373,17 +373,17 @@ class AbstractController extends Base {
373
373
  * You should provide path relative to controller and then array of middlewares to apply.
374
374
  * Order is matter.
375
375
  * Be default path apply to ANY' method, but you can preattach 'METHOD' into patch to scope patch to this METHOD
376
- * @returns {Map<string, Array<AbstractMiddleware | [Function, ...any]>>}
376
+ * @returns {Map<string, Array<typeof import('../services/http/middleware/AbstractMiddleware.js').default | [Function, ...any]>>}
377
377
  * @example
378
378
  * return new Map([
379
- * ['/*', [GetUserByToken]] // for any method for this controller
379
+ * ['/{*splat}', [GetUserByToken]] // for any method for this controller
380
380
  * ['POST/', [Auth]] // for POST method
381
381
  * ['/superSecretMethod', [OnlySuperSecretUsers]] // route with ANY method
382
382
  * ['PUT/superSecretMathod', [OnlySuperSecretAdmin]] // route with PUT method
383
383
  * ]);
384
384
  */
385
385
  static get middleware() {
386
- return new Map([['/*', [GetUserByToken, Auth]]]);
386
+ return new Map([['/{*splat}', [GetUserByToken, Auth]]]);
387
387
  }
388
388
 
389
389
  /**
@@ -0,0 +1,48 @@
1
+ import type Base from './Base.js';
2
+ import { Model, Schema } from 'mongoose';
3
+ import type Server from '../server.js';
4
+
5
+ interface AbstractModel<T extends Document> extends Model, Base {
6
+ constructor(app: Server['app'], callback?: () => void);
7
+
8
+ /**
9
+ * Return itself for internal methods.
10
+ */
11
+ getSuper(): this;
12
+
13
+ /**
14
+ * Model schema in Js object (not a mongoose schema).
15
+ */
16
+ get modelSchema(): Object;
17
+
18
+ /**
19
+ * Mongoose schema.
20
+ */
21
+ mongooseSchema: Schema<T>;
22
+
23
+ /**
24
+ * Acces to mongoose model too
25
+ */
26
+ mongooseModel: Model<T>;
27
+
28
+ /**
29
+ * Init custom hooks before model
30
+ */
31
+ initHooks(): void;
32
+ }
33
+
34
+ abstract class AbstractModel<T extends Document>
35
+ extends Model
36
+ implements AbstractModel
37
+ {
38
+ abstract get modelSchema(): Object;
39
+
40
+ /**
41
+ * Return itself for internal methods.
42
+ */
43
+ static abstract getSuper(): this;
44
+
45
+ mongooseSchema: Schema<T> = new Schema<T>(this.modelSchema);
46
+ }
47
+
48
+ export default AbstractModel;
@@ -2,13 +2,20 @@ import mongoose from 'mongoose';
2
2
  import Base from './Base.js';
3
3
 
4
4
  class AbstractModel extends Base {
5
+ mongooseSchema = null;
6
+
7
+ mongooseModel = null;
8
+
5
9
  /**
6
10
  * @param {import('../server.js').default['app']} app //TODO change to *.d.ts as this is a Server, not app
7
11
  * @param function callback optional callback when connection ready
8
12
  */
9
13
  constructor(app, callback = () => {}) {
10
14
  super(app);
11
- this.mongooseSchema = new mongoose.Schema(this.modelSchema);
15
+ this.mongooseSchema = new mongoose.Schema(
16
+ this.modelSchema,
17
+ this.modelSchemaOptions,
18
+ );
12
19
  mongoose.set('strictQuery', true);
13
20
  this.mongooseSchema.set('timestamps', true);
14
21
  this.mongooseSchema.set('minimize', false);
@@ -54,6 +61,14 @@ class AbstractModel extends Base {
54
61
  return {};
55
62
  }
56
63
 
64
+ /**
65
+ * Mongoose schema options
66
+ */
67
+ // eslint-disable-next-line class-methods-use-this
68
+ get modelSchemaOptions() {
69
+ return {};
70
+ }
71
+
57
72
  static get loggerGroup() {
58
73
  return 'model';
59
74
  }
package/modules/Base.d.ts CHANGED
@@ -1,6 +1,6 @@
1
- import winston from 'winston';
2
- import Server from '../server.js';
3
- import type { Dirent } from 'fs';
1
+ import type winston from 'winston';
2
+ import type Server from '../server.js';
3
+ import type { Dirent } from 'node.fs';
4
4
 
5
5
  declare class Base {
6
6
  app: Server['app'];
@@ -27,7 +27,7 @@ declare class Base {
27
27
  getFilesPathWithInheritance(
28
28
  internalFolder: string,
29
29
  externalFolder: string,
30
- ): Promise<Dirent[]>;
30
+ ): Promise<{ path: string; file: string }[]>;
31
31
 
32
32
  /**
33
33
  * Return logger group. Just to have all logs groupped logically
package/modules/Base.js CHANGED
@@ -18,7 +18,17 @@ class Base {
18
18
  * Optimzation to lazy load logger. It will be inited only on request
19
19
  */
20
20
  get logger() {
21
- if (!this.#realLogger) {
21
+ let l;
22
+ try {
23
+ l = this.#realLogger;
24
+ } catch (e) {
25
+ console.warn(
26
+ `You try to accees logger not from class. that can be ok in case of models.`,
27
+ );
28
+ return null;
29
+ }
30
+
31
+ if (!l) {
22
32
  this.#realLogger = this.getLogger(
23
33
  this.constructor.loggerGroup + this.getConstructorName(),
24
34
  );
@@ -29,24 +29,39 @@ class Cli extends Base {
29
29
  return true;
30
30
  }
31
31
 
32
+ async printComandTable() {
33
+ const commands = Object.keys(this.commands);
34
+ const maxLength = commands.reduce((max, c) => Math.max(max, c.length), 0);
35
+ console.log('Available commands:');
36
+ let commandsClasses = [];
37
+ for (const c of commands) {
38
+ // eslint-disable-next-line no-await-in-loop
39
+ commandsClasses.push(import(this.commands[c]));
40
+ // console.log(
41
+ // ` \x1b[36m${c.padEnd(maxLength)}\x1b[0m - ${f.default.description}`,
42
+ // );
43
+ }
44
+ commandsClasses = await Promise.all(commandsClasses);
45
+ for (const [key, c] of Object.entries(commands)) {
46
+ // eslint-disable-next-line no-await-in-loop
47
+ console.log(
48
+ ` \x1b[36m${c.padEnd(maxLength)}\x1b[0m - ${commandsClasses[key].default.description}`,
49
+ );
50
+ }
51
+ }
52
+
32
53
  async run(command, args) {
33
54
  await this.loadCommands();
34
55
 
35
56
  if (!command) {
36
57
  console.log('Please provide command name');
37
- console.log(
38
- 'Availalble commands:',
39
- Object.keys(this.commands).join(', '),
40
- );
58
+ await this.printComandTable();
41
59
  return false;
42
60
  }
43
61
 
44
62
  if (!this.commands[command]) {
45
63
  console.log(`Command ${command} not found `);
46
- console.log(
47
- 'Availalble commands:',
48
- Object.keys(this.commands).join(', '),
49
- );
64
+ await this.printComandTable();
50
65
  return false;
51
66
  }
52
67
  const { default: Command } = await import(this.commands[command]);
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@adaptivestone/framework",
3
- "version": "5.0.0-alpha.9",
3
+ "version": "5.0.0-beta.1",
4
4
  "description": "Adaptive stone node js framework",
5
5
  "main": "index.js",
6
6
  "type": "module",
@@ -16,6 +16,7 @@
16
16
  "dev": "node --watch ./index.js",
17
17
  "prod": "node --watch ./cluster.js",
18
18
  "test": "vitest run",
19
+ "t": "vitest --coverage=false --reporter=default",
19
20
  "prettier": "prettier --check '**/*.(js|jsx|ts|tsx|json|css|scss|md)'",
20
21
  "lint": "eslint '**/*.js'",
21
22
  "lint:fix": "eslint '**/*.js' --fix",
@@ -30,14 +31,12 @@
30
31
  "license": "MIT",
31
32
  "dependencies": {
32
33
  "deepmerge": "^4.2.2",
33
- "express": "^4.17.1",
34
+ "express": "^5.0.1",
34
35
  "formidable": "^3.5.1",
35
36
  "html-to-text": "^9.0.3",
36
- "i18next": "^23.2.8",
37
- "i18next-chained-backend": "^4.0.0",
37
+ "i18next": "^24.0.0",
38
38
  "i18next-fs-backend": "^2.0.0",
39
- "juice": "^10.0.0",
40
- "mime": "^4.0.0",
39
+ "juice": "^11.0.0",
41
40
  "minimist": "^1.2.5",
42
41
  "mongoose": "^8.0.0",
43
42
  "nodemailer": "^6.6.3",
@@ -47,21 +46,21 @@
47
46
  "rate-limiter-flexible": "^5.0.0",
48
47
  "redis": "^4.3.1",
49
48
  "winston": "^3.3.3",
50
- "winston-transport-sentry-node": "^2.0.0",
49
+ "winston-transport-sentry-node": "^3.0.0",
51
50
  "yup": "^1.0.0"
52
51
  },
53
52
  "devDependencies": {
54
- "@vitest/coverage-v8": "^2.0.0",
53
+ "@vitest/coverage-v8": "^3.0.0",
55
54
  "eslint": "^8.0.0",
56
55
  "eslint-config-airbnb-base": "^15.0.0",
57
- "eslint-config-prettier": "^9.0.0",
56
+ "eslint-config-prettier": "^10.0.0",
58
57
  "eslint-plugin-prettier": "^5.0.0",
59
58
  "eslint-plugin-vitest": "^0.4.0",
60
59
  "husky": "^9.0.0",
61
60
  "lint-staged": "^15.0.0",
62
- "mongodb-memory-server": "^9.0.0",
61
+ "mongodb-memory-server": "^10.0.0",
63
62
  "prettier": "^3.0.0",
64
- "vitest": "^2.0.0"
63
+ "vitest": "^3.0.0"
65
64
  },
66
65
  "lint-staged": {
67
66
  "**/*.{js,jsx,ts,tsx,json,css,scss,md}": [
package/server.js CHANGED
@@ -66,7 +66,7 @@ class Server {
66
66
 
67
67
  /**
68
68
  * Start server (http + init all http ralated functions)
69
- * @param <Promise>callbackBefore404 code that should be executed before adding page 404
69
+ * @param {Function} callbackBefore404 code that should be executed before adding page 404
70
70
  * @returns {Promise}
71
71
  */
72
72
  async startServer(callbackBefore404 = async () => Promise.resolve()) {
@@ -43,8 +43,10 @@ class Cache extends Base {
43
43
  }
44
44
  const key = this.getKeyWithNameSpace(keyValue);
45
45
  // 5 mins default
46
- let resolve = null;
47
- let reject = null;
46
+ // eslint-disable-next-line no-unused-vars
47
+ let resolve = (value) => {};
48
+ // eslint-disable-next-line no-unused-vars
49
+ let reject = (value) => {};
48
50
  if (this.promiseMapping.has(key)) {
49
51
  return this.promiseMapping.get(key);
50
52
  }
@@ -71,7 +73,7 @@ class Cache extends Base {
71
73
 
72
74
  this.redisClient.set(
73
75
  key,
74
- JSON.stringify(result, (jsonkey, value) =>
76
+ JSON.stringify(result, (_jsonkey, value) =>
75
77
  typeof value === 'bigint' ? `${value}n` : value,
76
78
  ),
77
79
  {
@@ -86,7 +88,7 @@ class Cache extends Base {
86
88
  )}`,
87
89
  );
88
90
  try {
89
- result = JSON.parse(result, (jsonkey, value) => {
91
+ result = JSON.parse(result, (_jsonkey, value) => {
90
92
  if (typeof value === 'string' && /^\d+n$/.test(value)) {
91
93
  return BigInt(value.slice(0, value.length - 1));
92
94
  }
@@ -1,11 +1,12 @@
1
1
  import http from 'node:http';
2
- import path from 'node:path';
3
- import * as url from 'node:url';
2
+ // import path from 'node:path';
3
+ // import * as url from 'node:url';
4
4
  import express from 'express';
5
5
  import RequestLoggerMiddleware from './middleware/RequestLogger.js';
6
6
  import I18nMiddleware from './middleware/I18n.js';
7
7
  import PrepareAppInfoMiddleware from './middleware/PrepareAppInfo.js';
8
8
  import RequestParserMiddleware from './middleware/RequestParser.js';
9
+ import IpDetector from './middleware/IpDetector.js';
9
10
  import Cors from './middleware/Cors.js';
10
11
  import Base from '../../modules/Base.js';
11
12
 
@@ -17,15 +18,16 @@ class HttpServer extends Base {
17
18
  super(app);
18
19
  this.express = express();
19
20
  this.express.disable('x-powered-by');
20
- const dirname = url.fileURLToPath(new URL('.', import.meta.url));
21
- this.express.set('views', [
22
- this.app.foldersConfig.views,
23
- path.join(dirname, '../../views'),
24
- ]);
25
- this.express.set('view engine', 'pug');
21
+ // const dirname = url.fileURLToPath(new URL('.', import.meta.url));
22
+ // this.express.set('views', [
23
+ // this.app.foldersConfig.views,
24
+ // path.join(dirname, '../../views'),
25
+ // ]);
26
+ // this.express.set('view engine', 'pug');
26
27
 
27
- this.express.use(new PrepareAppInfoMiddleware(this.app).getMiddleware());
28
28
  this.express.use(new RequestLoggerMiddleware(this.app).getMiddleware());
29
+ this.express.use(new PrepareAppInfoMiddleware(this.app).getMiddleware());
30
+ this.express.use(new IpDetector(this.app).getMiddleware());
29
31
  this.express.use(new I18nMiddleware(this.app).getMiddleware());
30
32
 
31
33
  const httpConfig = this.app.getConfig('http');