@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.
- package/CHANGELOG.md +123 -1
- package/Cli.js +3 -4
- package/cluster.js +0 -2
- package/commands/CreateUser.js +35 -0
- package/commands/Documentation.js +4 -0
- package/commands/DropIndex.js +14 -5
- package/commands/GenerateRandomBytes.js +21 -0
- package/commands/GetOpenApiJson.js +17 -2
- package/commands/SyncIndexes.js +1 -0
- package/commands/migration/Create.js +21 -10
- package/commands/migration/Migrate.js +1 -0
- package/config/auth.js +4 -1
- package/config/ipDetector.js +14 -0
- package/controllers/Auth.js +22 -31
- package/controllers/Home.js +1 -1
- package/eslint.config.js +68 -0
- package/folderConfig.js +0 -1
- package/helpers/files.js +9 -12
- package/helpers/logger.js +0 -1
- package/helpers/yup.js +2 -4
- package/jsconfig.json +4 -4
- package/models/Lock.js +107 -0
- package/models/User.js +26 -3
- package/modules/AbstractCommand.js +26 -2
- package/modules/AbstractController.js +19 -26
- package/modules/AbstractModel.d.ts +48 -0
- package/modules/AbstractModel.js +37 -10
- package/modules/Base.d.ts +4 -4
- package/modules/Base.js +13 -2
- package/modules/BaseCli.js +99 -11
- package/package.json +28 -25
- package/server.d.ts +9 -7
- package/server.js +45 -11
- package/services/cache/Cache.d.ts +1 -1
- package/services/cache/Cache.js +9 -7
- package/services/http/HttpServer.js +11 -16
- package/services/http/middleware/AbstractMiddleware.js +3 -3
- package/services/http/middleware/GetUserByToken.js +3 -2
- package/services/http/middleware/I18n.js +22 -23
- package/services/http/middleware/IpDetector.js +59 -0
- package/services/http/middleware/Pagination.js +7 -6
- package/services/http/middleware/RateLimiter.js +10 -4
- package/services/http/middleware/RequestLogger.js +3 -3
- package/services/http/middleware/RequestParser.js +1 -1
- package/services/messaging/email/templates/.gitkeep +0 -0
- package/services/validate/ValidateService.js +5 -5
- package/services/validate/drivers/AbstractValidator.js +2 -2
- package/services/validate/drivers/CustomValidator.js +2 -2
- package/services/validate/drivers/YupValidator.js +3 -3
- package/tests/setup.js +8 -6
- package/tests/setupVitest.js +9 -7
- package/types/ICommandArguments.d.ts +41 -0
- package/types/TFoldersConfig.d.ts +7 -4
- package/vitest.config.js +4 -3
- package/.eslintrc.cjs +0 -41
- package/commands/Generate.js +0 -14
- package/config/mail.js +0 -29
- package/controllers/Auth.test.js +0 -451
- package/controllers/Home.test.js +0 -12
- package/models/Migration.test.js +0 -20
- package/models/Sequence.test.js +0 -43
- package/models/User.test.js +0 -143
- package/modules/Modules.test.js +0 -18
- package/services/cache/Cache.test.js +0 -81
- package/services/http/middleware/Auth.test.js +0 -57
- package/services/http/middleware/Cors.test.js +0 -147
- package/services/http/middleware/GetUserByToken.test.js +0 -108
- package/services/http/middleware/I18n.test.js +0 -96
- package/services/http/middleware/PrepareAppInfo.test.js +0 -26
- package/services/http/middleware/RateLimiter.test.js +0 -233
- package/services/http/middleware/RequestParser.test.js +0 -121
- package/services/http/middleware/Role.test.js +0 -93
- package/services/messaging/email/index.js +0 -217
- package/services/messaging/email/templates/emptyTemplate/html.pug +0 -9
- package/services/messaging/email/templates/emptyTemplate/subject.pug +0 -1
- package/services/messaging/email/templates/emptyTemplate/text.pug +0 -1
- package/services/messaging/index.js +0 -3
- 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
|
|
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
|
|
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
|
package/commands/CreateUser.js
CHANGED
|
@@ -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 = [];
|
package/commands/DropIndex.js
CHANGED
|
@@ -5,12 +5,21 @@ class DropIndex extends AbstractCommand {
|
|
|
5
5
|
return 'Drop indexes of model';
|
|
6
6
|
}
|
|
7
7
|
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
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
|
|
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
|
|
package/commands/SyncIndexes.js
CHANGED
|
@@ -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
|
-
|
|
26
|
+
this.logger.error('Command cant start from nubmer');
|
|
27
|
+
return false;
|
|
18
28
|
}
|
|
19
|
-
const fileName = `${Date.now()}_${
|
|
29
|
+
const fileName = `${Date.now()}_${CreateMigration.camelSentence(
|
|
20
30
|
this.args.name,
|
|
21
31
|
)}.js`;
|
|
22
32
|
|
|
23
|
-
const fileContent =
|
|
24
|
-
|
|
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
|
-
|
|
41
|
+
this.logger.info(`Migration created ${fileName}`);
|
|
42
|
+
return true;
|
|
32
43
|
}
|
|
33
44
|
|
|
34
45
|
static camelSentence(str) {
|
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 ||
|
|
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
|
+
};
|
package/controllers/Auth.js
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import
|
|
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:
|
|
13
|
-
email:
|
|
14
|
-
password:
|
|
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:
|
|
20
|
-
email:
|
|
21
|
-
.string()
|
|
19
|
+
request: object().shape({
|
|
20
|
+
email: string()
|
|
22
21
|
.email('auth.emailValid')
|
|
23
22
|
.required('auth.emailProvided'),
|
|
24
|
-
password:
|
|
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:
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
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:
|
|
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:
|
|
49
|
-
password:
|
|
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:
|
|
52
|
+
passwordRecoveryToken: string().required(),
|
|
57
53
|
}),
|
|
58
54
|
},
|
|
59
55
|
'/send-verification': {
|
|
60
56
|
handler: this.sendVerification,
|
|
61
|
-
request:
|
|
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
|
-
|
|
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
|
|
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([['
|
|
197
|
+
return new Map([['/{*splat}', [GetUserByToken, RateLimiter]]]);
|
|
207
198
|
}
|
|
208
199
|
}
|
|
209
200
|
|
package/controllers/Home.js
CHANGED
package/eslint.config.js
ADDED
|
@@ -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
|
-
|
|
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
|
-
|
|
36
|
+
const internalFilesString = internalFiles
|
|
37
37
|
.filter(filterIndexFile)
|
|
38
38
|
.map((fileDirent) =>
|
|
39
|
-
join(fileDirent.
|
|
39
|
+
join(fileDirent.parentPath, fileDirent.name)
|
|
40
40
|
.replace(`${internalFolder}/`, '')
|
|
41
41
|
.replace(`${internalFolder}`, ''),
|
|
42
42
|
);
|
|
43
|
-
|
|
43
|
+
const externalFilesString = externalFiles
|
|
44
44
|
.filter(filterIndexFile)
|
|
45
45
|
.map((fileDirent) =>
|
|
46
|
-
join(fileDirent.
|
|
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
|
|
53
|
-
if (
|
|
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
|
|
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 };
|