@adaptivestone/framework 5.0.0-alpha.9 → 5.0.0-beta.10

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 (78) hide show
  1. package/CHANGELOG.md +123 -1
  2. package/Cli.js +3 -4
  3. package/cluster.js +0 -2
  4. package/commands/CreateUser.js +35 -0
  5. package/commands/Documentation.js +4 -0
  6. package/commands/DropIndex.js +14 -5
  7. package/commands/GenerateRandomBytes.js +21 -0
  8. package/commands/GetOpenApiJson.js +17 -2
  9. package/commands/SyncIndexes.js +1 -0
  10. package/commands/migration/Create.js +21 -10
  11. package/commands/migration/Migrate.js +1 -0
  12. package/config/auth.js +4 -1
  13. package/config/ipDetector.js +14 -0
  14. package/controllers/Auth.js +22 -31
  15. package/controllers/Home.js +1 -1
  16. package/eslint.config.js +68 -0
  17. package/folderConfig.js +0 -1
  18. package/helpers/files.js +9 -12
  19. package/helpers/logger.js +0 -1
  20. package/helpers/yup.js +2 -4
  21. package/jsconfig.json +4 -4
  22. package/models/Lock.js +107 -0
  23. package/models/User.js +26 -3
  24. package/modules/AbstractCommand.js +26 -2
  25. package/modules/AbstractController.js +19 -26
  26. package/modules/AbstractModel.d.ts +48 -0
  27. package/modules/AbstractModel.js +37 -10
  28. package/modules/Base.d.ts +4 -4
  29. package/modules/Base.js +13 -2
  30. package/modules/BaseCli.js +99 -11
  31. package/package.json +28 -25
  32. package/server.d.ts +9 -7
  33. package/server.js +45 -11
  34. package/services/cache/Cache.d.ts +1 -1
  35. package/services/cache/Cache.js +9 -7
  36. package/services/http/HttpServer.js +11 -16
  37. package/services/http/middleware/AbstractMiddleware.js +3 -3
  38. package/services/http/middleware/GetUserByToken.js +3 -2
  39. package/services/http/middleware/I18n.js +22 -23
  40. package/services/http/middleware/IpDetector.js +59 -0
  41. package/services/http/middleware/Pagination.js +7 -6
  42. package/services/http/middleware/RateLimiter.js +10 -4
  43. package/services/http/middleware/RequestLogger.js +3 -3
  44. package/services/http/middleware/RequestParser.js +1 -1
  45. package/services/messaging/email/templates/.gitkeep +0 -0
  46. package/services/validate/ValidateService.js +5 -5
  47. package/services/validate/drivers/AbstractValidator.js +2 -2
  48. package/services/validate/drivers/CustomValidator.js +2 -2
  49. package/services/validate/drivers/YupValidator.js +3 -3
  50. package/tests/setup.js +8 -6
  51. package/tests/setupVitest.js +9 -7
  52. package/types/ICommandArguments.d.ts +41 -0
  53. package/types/TFoldersConfig.d.ts +7 -4
  54. package/vitest.config.js +4 -3
  55. package/.eslintrc.cjs +0 -41
  56. package/commands/Generate.js +0 -14
  57. package/config/mail.js +0 -29
  58. package/controllers/Auth.test.js +0 -451
  59. package/controllers/Home.test.js +0 -12
  60. package/models/Migration.test.js +0 -20
  61. package/models/Sequence.test.js +0 -43
  62. package/models/User.test.js +0 -143
  63. package/modules/Modules.test.js +0 -18
  64. package/services/cache/Cache.test.js +0 -81
  65. package/services/http/middleware/Auth.test.js +0 -57
  66. package/services/http/middleware/Cors.test.js +0 -147
  67. package/services/http/middleware/GetUserByToken.test.js +0 -108
  68. package/services/http/middleware/I18n.test.js +0 -96
  69. package/services/http/middleware/PrepareAppInfo.test.js +0 -26
  70. package/services/http/middleware/RateLimiter.test.js +0 -233
  71. package/services/http/middleware/RequestParser.test.js +0 -121
  72. package/services/http/middleware/Role.test.js +0 -93
  73. package/services/messaging/email/index.js +0 -217
  74. package/services/messaging/email/templates/emptyTemplate/html.pug +0 -9
  75. package/services/messaging/email/templates/emptyTemplate/subject.pug +0 -1
  76. package/services/messaging/email/templates/emptyTemplate/text.pug +0 -1
  77. package/services/messaging/index.js +0 -3
  78. package/services/validate/ValidateService.test.js +0 -107
package/CHANGELOG.md CHANGED
@@ -1,3 +1,125 @@
1
+ ### 5.0.0-beta.9
2
+
3
+ [BREAKING] move email module to separate package @adaptivestone/framework-module-email. Please use it if you want to send emails
4
+ [NEW] app now contains 'frameworkFolder' folder the framework located. Mostly for modules usage
5
+ [BREAKING] remove VIEWS folders at all. Should not afffect any user as this was not used internally
6
+ [UPDATE] update typing
7
+ [UPDATE] change redis -> @redis/client as we are using only client from pakage
8
+ [BREAKING] removed noidemailer-sendmail-transport. Not needed anymore and not recommended to use as well
9
+
10
+ ### 5.0.0-beta.8
11
+
12
+ [UPDATE] update deps
13
+ [NEW] Lock model for working locks via mongoDB
14
+
15
+ ### 5.0.0-beta.7
16
+
17
+ [UPDATE] update deps
18
+ [UPDATE] change vitest shutdown behavior as mongo driver v6.13 change befaviur that affect us (MongoClient.close now closes any outstanding cursors)
19
+
20
+ ### 5.0.0-beta.5
21
+
22
+ [BREAKING] remove minimist CLI parsing and replace it by commandArguments parser
23
+ [UPDATE] migrated from eslint-plugin-import to eslint-plugin-import-x
24
+
25
+ ### 5.0.0-beta.5
26
+
27
+ [UPDATE] migrate to eslint 9 and away from aibnb styles (they are abonded)
28
+
29
+ ### 5.0.0-beta.4
30
+
31
+ [NEW] on shutdown event now after timeout we are forcing to shutdown
32
+
33
+ ### 5.0.0-beta.2
34
+
35
+ [UPDATE] update deps
36
+ [NEW] add ability to skip mongo model init in CLI env
37
+ [NEW] now each mongo connection on CLI have own name and inslude command name there too (getMongoConnectionName in command)
38
+
39
+ ### 5.0.0-beta.1
40
+
41
+ [UPDATE] update deps
42
+ [BREAKING] vitest v3 https://vitest.dev/guide/migration.html
43
+
44
+ ### 5.0.0-alpha.26
45
+
46
+ [UPDATE] update deps
47
+ [UPDATE] new commands view in CLI
48
+
49
+ ### 5.0.0-alpha.24
50
+
51
+ [UPDATE] update deps
52
+ [BREAKING] i18next v24 https://www.i18next.com/misc/migration-guide#v23.x.x-to-v24.0.0
53
+
54
+ ### 5.0.0-alpha.23
55
+
56
+ [UPDATE] update deps
57
+
58
+ ### 5.0.0-alpha.22
59
+
60
+ [UPDATE] update deps
61
+ [FIX] fix optional routing parameters
62
+
63
+ ### 5.0.0-alpha.21
64
+
65
+ [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.
66
+ [BREAKING] AS part of express 5 migration _ in rotes (middlewares) should have perameter. please replace _ to \*splat
67
+ [UPDATE] update deps
68
+ [UPDATE] Mailer uses await import() for startup speedup
69
+
70
+ ### 5.0.0-alpha.20
71
+
72
+ [UPDATE] update deps
73
+ [UPDATE] #realLogger do not throw error in a scecific cases (model toJSON({virtual:true}))
74
+
75
+ ### 5.0.0-alpha.19
76
+
77
+ [NEW] added modelSchemaOptions for models
78
+
79
+ ### 5.0.0-alpha.18
80
+
81
+ [BREAKING] default auth responce changed to be unified. {token, user} = > {data:{token, user}}
82
+ [UPDATE] RateLimiter updae key generation
83
+
84
+ ### 5.0.0-alpha.17
85
+
86
+ [NEW] generateRandomBytes command
87
+ [UPDATE] update deps
88
+
89
+ ### 5.0.0-alpha.16
90
+
91
+ [UPDATE] no warning of direct usage body and query
92
+ [UPDATE] update deps
93
+
94
+ ### 5.0.0-alpha.15
95
+
96
+ [BUG] fix bug with pagination
97
+ [UPDATE] update deps
98
+
99
+ ### 5.0.0-alpha.14
100
+
101
+ [NEW] add types for Abstract model (wip)
102
+
103
+ ### 5.0.0-alpha.13
104
+
105
+ [UPDATE] update deps
106
+ [UPDATE] update i18n internal implementation
107
+ [CHANGE] disable https server view
108
+
109
+ ### 5.0.0-alpha.12
110
+
111
+ [UPDATE] update deps
112
+
113
+ ### 5.0.0-alpha.11
114
+
115
+ [UPDATE] update deps
116
+
117
+ ### 5.0.0-alpha.10
118
+
119
+ [UPDATE] update deps
120
+ [NEW] IpDetector middleware that support detecting proxy and X-Forwarded-For header
121
+ [BREAKING] RateLimiter now need to have IpDetector middleware before
122
+
1
123
  ### 5.0.0-alpha.9
2
124
 
3
125
  [UPDATE] update deps
@@ -368,7 +490,7 @@ await doc.populate([
368
490
  [UPDATE] update deps
369
491
  [UPDATE] winston console transport now using timestapms
370
492
  [UPDATE] PrepareAppInfo middleware now a global one. Do not need to include it on every controller
371
- [NEW] Request anso works with req.query, but req.body have bigger priority
493
+ [NEW] Request also works with req.query, but req.body have bigger priority
372
494
 
373
495
  ### 2.18.0
374
496
 
package/Cli.js CHANGED
@@ -1,4 +1,3 @@
1
- import parseArgs from 'minimist';
2
1
  import mongoose from 'mongoose';
3
2
  import BaseCli from './modules/BaseCli.js';
4
3
  import Server from './server.js';
@@ -8,14 +7,14 @@ class Cli extends BaseCli {
8
7
  mongoose.set('autoIndex', false); // we do not need create indexes on CLI.
9
8
  const server = new Server(serverConfig);
10
9
  super(server);
11
- this.args = parseArgs(process.argv.slice(3));
12
10
  }
13
11
 
14
12
  async run() {
15
- await this.server.init();
13
+ await this.server.init({ isSkipModelInit: true, isSkipModelLoading: true });
16
14
  const command = process.argv[2]?.toLowerCase();
17
- await super.run(command, this.args);
15
+ await super.run(command);
18
16
  this.app.events.emit('shutdown');
17
+ return true;
19
18
  }
20
19
  }
21
20
 
package/cluster.js CHANGED
@@ -4,7 +4,6 @@ import { cpus } from 'node:os';
4
4
  const numCPUs = cpus().length;
5
5
 
6
6
  if (cluster.isPrimary) {
7
- // eslint-disable-next-line no-console
8
7
  console.log(`Master ${process.pid} is running`);
9
8
  // Fork workers.
10
9
  for (let i = 0; i < numCPUs; i += 1) {
@@ -12,7 +11,6 @@ if (cluster.isPrimary) {
12
11
  }
13
12
 
14
13
  cluster.on('exit', (worker, code, signal) => {
15
- // eslint-disable-next-line no-console
16
14
  console.log(
17
15
  `Worker \x1B[45m ${
18
16
  worker.process.pid
@@ -2,6 +2,41 @@ 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
+
9
+ /**
10
+ * You able to add command arguments for parsing there.
11
+ * @returns {import("../types/ICommandArguments.js").ICommandArguments}
12
+ */
13
+ static get commandArguments() {
14
+ return {
15
+ id: {
16
+ type: 'string',
17
+ description: 'User id to find user',
18
+ },
19
+ email: {
20
+ type: 'string',
21
+ description: 'User id to find/create user',
22
+ },
23
+ password: {
24
+ type: 'string',
25
+ description: 'New password for user',
26
+ },
27
+ roles: {
28
+ type: 'string',
29
+ description:
30
+ 'User roles comma separated string (--roles=user,admin,someOtherRoles)',
31
+ },
32
+ update: {
33
+ type: 'boolean',
34
+ default: false,
35
+ description: 'Update user if it exists',
36
+ },
37
+ };
38
+ }
39
+
5
40
  async run() {
6
41
  const User = this.app.getModel('User');
7
42
  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 = [];
@@ -5,12 +5,21 @@ class DropIndex extends AbstractCommand {
5
5
  return 'Drop indexes of model';
6
6
  }
7
7
 
8
- async run() {
9
- if (!this.args.model) {
10
- this.logger.error('Please provide model name as "--model=BestUserModel"');
11
- return false;
12
- }
8
+ /**
9
+ * You able to add command arguments for parsing there.
10
+ * @returns {import("../types/ICommandArguments.js").ICommandArguments}
11
+ */
12
+ static get commandArguments() {
13
+ return {
14
+ model: {
15
+ type: 'string',
16
+ description: 'Model name',
17
+ required: true,
18
+ },
19
+ };
20
+ }
13
21
 
22
+ async run() {
14
23
  const Model = this.app.getModel(this.args.model);
15
24
 
16
25
  if (!Model) {
@@ -0,0 +1,21 @@
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
+ static isShouldInitModels = false;
10
+
11
+ async run() {
12
+ const sizes = [16, 32, 64, 128, 256];
13
+ for (const size of sizes) {
14
+ const bytes = randomBytes(size).toString('hex');
15
+ this.logger.info(`${size} bytes: ${bytes}`);
16
+ }
17
+ return true;
18
+ }
19
+ }
20
+
21
+ export default GenerateRandomBytes;
@@ -5,6 +5,22 @@ 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
+ /**
12
+ * You able to add command arguments for parsing there.
13
+ * @returns {import("../types/ICommandArguments.js").ICommandArguments}
14
+ */
15
+ static get commandArguments() {
16
+ return {
17
+ output: {
18
+ type: 'string',
19
+ description: 'Output file path',
20
+ },
21
+ };
22
+ }
23
+
8
24
  async run() {
9
25
  const { myDomain } = this.app.getConfig('http');
10
26
  let jsonFile = process.env.npm_package_json;
@@ -14,7 +30,7 @@ class GetOpenApiJson extends AbstractCommand {
14
30
 
15
31
  try {
16
32
  jsonFile = JSON.parse(await fs.readFile(jsonFile, 'utf8'));
17
- } catch (e) {
33
+ } catch {
18
34
  this.logger.error(
19
35
  'No npm package detected. Please start this command via NPM as it depends on package.json',
20
36
  );
@@ -119,7 +135,6 @@ class GetOpenApiJson extends AbstractCommand {
119
135
 
120
136
  let routeName = Object.keys(route)[0];
121
137
  if (routeName === '/') {
122
- // eslint-disable-next-line no-continue
123
138
  continue;
124
139
  }
125
140
 
@@ -29,6 +29,7 @@ class SyncIndexes extends AbstractCommand {
29
29
  this.logger.info(`Model - ${modelName} NO removed indexes`);
30
30
  }
31
31
  }
32
+ return true;
32
33
  }
33
34
 
34
35
  static get description() {
@@ -7,28 +7,39 @@ class CreateMigration extends AbstractCommand {
7
7
  return 'Create new migration';
8
8
  }
9
9
 
10
+ /**
11
+ * You able to add command arguments for parsing there.
12
+ * @returns {import("../../types/ICommandArguments.js").ICommandArguments}
13
+ */
14
+ static get commandArguments() {
15
+ return {
16
+ name: {
17
+ type: 'string',
18
+ description: 'Migration name',
19
+ required: true,
20
+ },
21
+ };
22
+ }
23
+
10
24
  async run() {
11
- if (!this.args.name) {
12
- return this.logger.error(
13
- 'Please provide migration name with key "--name={someName}"',
14
- );
15
- }
16
25
  if (this.args.name.match(/^\d/)) {
17
- return this.logger.error('Command cant start from nubmer');
26
+ this.logger.error('Command cant start from nubmer');
27
+ return false;
18
28
  }
19
- const fileName = `${Date.now()}_${this.constructor.camelSentence(
29
+ const fileName = `${Date.now()}_${CreateMigration.camelSentence(
20
30
  this.args.name,
21
31
  )}.js`;
22
32
 
23
- const fileContent = this.constructor.getTemplate(
24
- this.constructor.camelSentence(this.args.name),
33
+ const fileContent = CreateMigration.getTemplate(
34
+ CreateMigration.camelSentence(this.args.name),
25
35
  );
26
36
 
27
37
  await fs.writeFile(
28
38
  path.join(this.app.foldersConfig.migrations, fileName),
29
39
  fileContent,
30
40
  );
31
- return this.logger.info(`Migration created ${fileName}`);
41
+ this.logger.info(`Migration created ${fileName}`);
42
+ return true;
32
43
  }
33
44
 
34
45
  static camelSentence(str) {
@@ -49,6 +49,7 @@ class Migrate extends AbstractCommand {
49
49
  this.logger.info(
50
50
  `=== Migration Finished. Migrated ${migrations.length} files ===`,
51
51
  );
52
+ return true;
52
53
  }
53
54
  }
54
55
 
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
+ };
@@ -1,4 +1,4 @@
1
- import yup from 'yup';
1
+ import { object, string } from 'yup';
2
2
  import AbstractController from '../modules/AbstractController.js';
3
3
  import GetUserByToken from '../services/http/middleware/GetUserByToken.js';
4
4
  import RateLimiter from '../services/http/middleware/RateLimiter.js';
@@ -9,58 +9,52 @@ class Auth extends AbstractController {
9
9
  post: {
10
10
  '/login': {
11
11
  handler: this.postLogin,
12
- request: yup.object().shape({
13
- email: yup.string().email().required('auth.emailProvided'), // if not provided then error will be generated
14
- password: yup.string().required('auth.passwordProvided'), // possible to provide values from translation
12
+ request: object().shape({
13
+ email: string().email().required('auth.emailProvided'), // if not provided then error will be generated
14
+ password: string().required('auth.passwordProvided'), // possible to provide values from translation
15
15
  }),
16
16
  },
17
17
  '/register': {
18
18
  handler: this.postRegister,
19
- request: yup.object().shape({
20
- email: yup
21
- .string()
19
+ request: object().shape({
20
+ email: string()
22
21
  .email('auth.emailValid')
23
22
  .required('auth.emailProvided'),
24
- password: yup
25
- .string()
23
+ password: string()
26
24
  .matches(
27
25
  /^[a-zA-Z0-9!@#$%ˆ^&*()_+\-{}[\]<>]+$/,
28
26
  'auth.passwordValid',
29
27
  )
30
28
  .required('auth.passwordProvided'),
31
- nickName: yup
32
- .string()
33
- .matches(/^[a-zA-Z0-9_\-.]+$/, 'auth.nickNameValid'),
34
- firstName: yup.string(),
35
- lastName: yup.string(),
29
+ nickName: string().matches(
30
+ /^[a-zA-Z0-9_\-.]+$/,
31
+ 'auth.nickNameValid',
32
+ ),
33
+ firstName: string(),
34
+ lastName: string(),
36
35
  }),
37
36
  },
38
37
  '/logout': this.postLogout,
39
38
  '/verify': this.verifyUser,
40
39
  '/send-recovery-email': {
41
40
  handler: this.sendPasswordRecoveryEmail,
42
- request: yup
43
- .object()
44
- .shape({ email: yup.string().email().required() }),
41
+ request: object().shape({ email: string().email().required() }),
45
42
  },
46
43
  '/recover-password': {
47
44
  handler: this.recoverPassword,
48
- request: yup.object().shape({
49
- password: yup
50
- .string()
45
+ request: object().shape({
46
+ password: string()
51
47
  .matches(
52
48
  /^[a-zA-Z0-9!@#$%ˆ^&*()_+\-{}[\]<>]+$/,
53
49
  'auth.passwordValid',
54
50
  )
55
51
  .required(),
56
- passwordRecoveryToken: yup.string().required(),
52
+ passwordRecoveryToken: string().required(),
57
53
  }),
58
54
  },
59
55
  '/send-verification': {
60
56
  handler: this.sendVerification,
61
- request: yup
62
- .object()
63
- .shape({ email: yup.string().email().required() }),
57
+ request: object().shape({ email: string().email().required() }),
64
58
  },
65
59
  },
66
60
  };
@@ -83,7 +77,7 @@ class Auth extends AbstractController {
83
77
  }
84
78
  const token = await user.generateToken();
85
79
 
86
- return res.status(200).json({ token, user: user.getPublic() });
80
+ return res.status(200).json({ data: { token, user: user.getPublic() } });
87
81
  }
88
82
 
89
83
  async postRegister(req, res) {
@@ -113,12 +107,9 @@ class Auth extends AbstractController {
113
107
 
114
108
  const { isAuthWithVefificationFlow } = this.app.getConfig('auth');
115
109
  if (isAuthWithVefificationFlow) {
116
- const answer = await user.sendVerificationEmail(req.i18n).catch((e) => {
110
+ await user.sendVerificationEmail(req.i18n).catch((e) => {
117
111
  this.logger.error(e);
118
112
  });
119
- if (!answer) {
120
- return res.status(500).json();
121
- }
122
113
  }
123
114
  return res.status(201).json();
124
115
  }
@@ -136,7 +127,7 @@ class Auth extends AbstractController {
136
127
  user = await User.getUserByVerificationToken(
137
128
  req.query.verification_token,
138
129
  );
139
- } catch (e) {
130
+ } catch {
140
131
  return res.status(400).json({
141
132
  message: req.i18n.t('email.alreadyVerifiedOrWrongToken'),
142
133
  });
@@ -203,7 +194,7 @@ class Auth extends AbstractController {
203
194
  }
204
195
 
205
196
  static get middleware() {
206
- return new Map([['/*', [GetUserByToken, RateLimiter]]]);
197
+ return new Map([['/{*splat}', [GetUserByToken, RateLimiter]]]);
207
198
  }
208
199
  }
209
200
 
@@ -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
 
@@ -0,0 +1,68 @@
1
+ import globals from 'globals';
2
+ import pluginJs from '@eslint/js';
3
+ import importPlugin from 'eslint-plugin-import-x';
4
+ import vitest from '@vitest/eslint-plugin';
5
+ import eslintConfigPrettier from 'eslint-config-prettier';
6
+ import prettierPlugin from 'eslint-plugin-prettier/recommended';
7
+
8
+ /** @type {import('eslint').Linter.Config[]} */
9
+ // @ts-ignore
10
+ export default [
11
+ pluginJs.configs.recommended,
12
+ importPlugin.flatConfigs.recommended,
13
+ eslintConfigPrettier,
14
+ prettierPlugin,
15
+ {
16
+ languageOptions: {
17
+ sourceType: 'module',
18
+ ecmaVersion: 'latest',
19
+ globals: {
20
+ ...globals.es2023,
21
+ ...globals.node,
22
+ },
23
+ },
24
+ },
25
+ {
26
+ rules: {
27
+ 'no-await-in-loop': 'error',
28
+ 'no-param-reassign': 'error',
29
+ 'class-methods-use-this': 'error',
30
+ 'no-shadow': 'error',
31
+ 'prefer-const': 'error',
32
+ 'import-x/no-extraneous-dependencies': ['error'],
33
+ 'import-x/first': ['error'],
34
+ camelcase: ['error', { properties: 'never', ignoreDestructuring: false }],
35
+ 'prefer-destructuring': [
36
+ 'error',
37
+ {
38
+ VariableDeclarator: {
39
+ array: false,
40
+ object: true,
41
+ },
42
+ AssignmentExpression: {
43
+ array: true,
44
+ object: false,
45
+ },
46
+ },
47
+ {
48
+ enforceForRenamedProperties: false,
49
+ },
50
+ ],
51
+ 'no-plusplus': 'error',
52
+ 'consistent-return': 'error',
53
+ 'no-return-await': 'error',
54
+ 'arrow-body-style': 'error',
55
+ 'dot-notation': 'error',
56
+ curly: 'error',
57
+ },
58
+ },
59
+ {
60
+ files: ['**/*.test.js'],
61
+ plugins: {
62
+ vitest,
63
+ },
64
+ rules: {
65
+ ...vitest.configs.recommended.rules,
66
+ },
67
+ },
68
+ ];
package/folderConfig.js CHANGED
@@ -5,7 +5,6 @@ export default {
5
5
  config: path.resolve('./config'),
6
6
  models: path.resolve('./models'),
7
7
  controllers: path.resolve('./controllers'),
8
- views: path.resolve('./views'),
9
8
  locales: path.resolve('./locales'),
10
9
  emails: path.resolve('./services/messaging/email/templates'),
11
10
  commands: path.resolve('./commands'),
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,
@@ -73,7 +73,4 @@ const getFilesPathWithInheritance = async ({
73
73
  return filesToLoad;
74
74
  };
75
75
 
76
- export {
77
- // eslint-disable-next-line import/prefer-default-export
78
- getFilesPathWithInheritance,
79
- };
76
+ export { getFilesPathWithInheritance };