@adaptivestone/framework 4.4.0 → 4.6.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.
- package/CHANGELOG.md +10 -0
- package/controllers/Auth.test.js +2 -0
- package/controllers/Home.test.js +2 -0
- package/controllers/index.js +20 -17
- package/coverage/base.css +224 -0
- package/coverage/block-navigation.js +87 -0
- package/coverage/clover.xml +3433 -0
- package/coverage/coverage-final.json +41 -0
- package/coverage/favicon.png +0 -0
- package/coverage/framework/config/auth.js.html +100 -0
- package/coverage/framework/config/http.js.html +112 -0
- package/coverage/framework/config/i18n.js.html +121 -0
- package/coverage/framework/config/index.html +236 -0
- package/coverage/framework/config/log.js.html +151 -0
- package/coverage/framework/config/mail.js.html +172 -0
- package/coverage/framework/config/mongo.js.html +94 -0
- package/coverage/framework/config/rateLimiter.js.html +133 -0
- package/coverage/framework/config/redis.js.html +97 -0
- package/coverage/framework/config/validate.js.html +94 -0
- package/coverage/framework/controllers/Auth.js.html +721 -0
- package/coverage/framework/controllers/Home.js.html +169 -0
- package/coverage/framework/controllers/index.html +146 -0
- package/coverage/framework/controllers/index.js.html +268 -0
- package/coverage/framework/controllers/test/SomeController.js.html +616 -0
- package/coverage/framework/controllers/test/index.html +116 -0
- package/coverage/framework/helpers/redis/clearNamespace.js.html +127 -0
- package/coverage/framework/helpers/redis/index.html +116 -0
- package/coverage/framework/index.html +116 -0
- package/coverage/framework/models/Sequence.js.html +151 -0
- package/coverage/framework/models/User.js.html +859 -0
- package/coverage/framework/models/index.html +131 -0
- package/coverage/framework/modules/AbstractController.js.html +1315 -0
- package/coverage/framework/modules/AbstractModel.js.html +268 -0
- package/coverage/framework/modules/Base.js.html +577 -0
- package/coverage/framework/modules/index.html +146 -0
- package/coverage/framework/server.js.html +820 -0
- package/coverage/framework/services/cache/Cache.js.html +430 -0
- package/coverage/framework/services/cache/index.html +116 -0
- package/coverage/framework/services/documentation/DocumentationGenerator.js.html +598 -0
- package/coverage/framework/services/documentation/index.html +116 -0
- package/coverage/framework/services/http/HttpServer.js.html +373 -0
- package/coverage/framework/services/http/index.html +116 -0
- package/coverage/framework/services/http/middleware/AbstractMiddleware.js.html +238 -0
- package/coverage/framework/services/http/middleware/Auth.js.html +145 -0
- package/coverage/framework/services/http/middleware/GetUserByToken.js.html +223 -0
- package/coverage/framework/services/http/middleware/I18n.js.html +442 -0
- package/coverage/framework/services/http/middleware/Pagination.js.html +253 -0
- package/coverage/framework/services/http/middleware/PrepareAppInfo.js.html +139 -0
- package/coverage/framework/services/http/middleware/RateLimiter.js.html +472 -0
- package/coverage/framework/services/http/middleware/RequestLogger.js.html +151 -0
- package/coverage/framework/services/http/middleware/RequestParser.js.html +199 -0
- package/coverage/framework/services/http/middleware/Role.js.html +172 -0
- package/coverage/framework/services/http/middleware/index.html +251 -0
- package/coverage/framework/services/http/middleware/test/CheckFlag.js.html +139 -0
- package/coverage/framework/services/http/middleware/test/index.html +116 -0
- package/coverage/framework/services/messaging/email/index.html +116 -0
- package/coverage/framework/services/messaging/email/index.js.html +739 -0
- package/coverage/framework/services/messaging/index.html +116 -0
- package/coverage/framework/services/messaging/index.js.html +100 -0
- package/coverage/framework/services/validate/ValidateService.js.html +568 -0
- package/coverage/framework/services/validate/drivers/AbstractValidator.js.html +196 -0
- package/coverage/framework/services/validate/drivers/CustomValidator.js.html +241 -0
- package/coverage/framework/services/validate/drivers/YupValidator.js.html +394 -0
- package/coverage/framework/services/validate/drivers/index.html +146 -0
- package/coverage/framework/services/validate/index.html +116 -0
- package/coverage/index.html +341 -0
- package/coverage/prettify.css +1 -0
- package/coverage/prettify.js +2 -0
- package/coverage/sort-arrow-sprite.png +0 -0
- package/coverage/sorter.js +196 -0
- package/models/Sequence.test.js +2 -0
- package/models/User.js +8 -8
- package/models/User.test.js +2 -0
- package/modules/AbstractModel.js +1 -0
- package/modules/BaseCli.js +2 -2
- package/modules/Modules.test.js +3 -2
- package/package.json +7 -18
- package/server.js +9 -9
- package/services/http/middleware/I18n.test.js +12 -5
- package/services/http/middleware/PrepareAppInfo.test.js +7 -3
- package/services/http/middleware/RateLimiter.js +5 -6
- package/services/http/middleware/RateLimiter.test.js +184 -1
- package/services/http/middleware/RequestParser.test.js +7 -4
- package/services/validate/ValidateService.test.js +2 -0
- package/tests/setup.js +2 -2
- package/tests/setupVitest.js +119 -0
- package/vitest.config.js +9 -0
|
@@ -1,6 +1,27 @@
|
|
|
1
|
-
|
|
1
|
+
import { setTimeout } from 'node:timers/promises';
|
|
2
|
+
import crypto from 'node:crypto';
|
|
3
|
+
import { beforeAll, afterAll, describe, it, expect } from 'vitest';
|
|
4
|
+
|
|
5
|
+
import RateLimiter from './RateLimiter';
|
|
6
|
+
|
|
7
|
+
let mongoRateLimiter;
|
|
2
8
|
|
|
3
9
|
describe('rate limiter methods', () => {
|
|
10
|
+
beforeAll(async () => {
|
|
11
|
+
await setTimeout(20);
|
|
12
|
+
|
|
13
|
+
mongoRateLimiter = new RateLimiter(global.server.app, {
|
|
14
|
+
driver: 'mongo',
|
|
15
|
+
limiterOptions: {
|
|
16
|
+
keyPrefix: `mongo_${Date.now()}_${crypto.randomUUID()}}`,
|
|
17
|
+
},
|
|
18
|
+
});
|
|
19
|
+
});
|
|
20
|
+
|
|
21
|
+
afterAll(async () => {
|
|
22
|
+
// we need to wait because redis mongo ask mongo to create indexes
|
|
23
|
+
await setTimeout(200);
|
|
24
|
+
});
|
|
4
25
|
it('have description fields', async () => {
|
|
5
26
|
expect.assertions(1);
|
|
6
27
|
const middleware = new RateLimiter(global.server.app, {
|
|
@@ -47,4 +68,166 @@ describe('rate limiter methods', () => {
|
|
|
47
68
|
|
|
48
69
|
expect(res).toBe('192.168.0.0__someId');
|
|
49
70
|
});
|
|
71
|
+
|
|
72
|
+
it('generateConsumeKey with request works correctly', async () => {
|
|
73
|
+
expect.assertions(1);
|
|
74
|
+
|
|
75
|
+
const redisRateLimiter = new RateLimiter(global.server.app, {
|
|
76
|
+
driver: 'redis',
|
|
77
|
+
consumeKeyComponents: {
|
|
78
|
+
request: ['email'],
|
|
79
|
+
},
|
|
80
|
+
});
|
|
81
|
+
|
|
82
|
+
const res = await redisRateLimiter.gerenateConsumeKey({
|
|
83
|
+
ip: '192.168.0.0',
|
|
84
|
+
body: {
|
|
85
|
+
email: 'foo@example.com',
|
|
86
|
+
},
|
|
87
|
+
});
|
|
88
|
+
|
|
89
|
+
expect(res).toBe('192.168.0.0__foo@example.com');
|
|
90
|
+
});
|
|
91
|
+
|
|
92
|
+
it('middleware without driver should fail', async () => {
|
|
93
|
+
expect.assertions(2);
|
|
94
|
+
const rateLimiter = new RateLimiter(global.server.app, {
|
|
95
|
+
driver: 'unknown',
|
|
96
|
+
});
|
|
97
|
+
const req = {
|
|
98
|
+
appInfo: {},
|
|
99
|
+
};
|
|
100
|
+
let status;
|
|
101
|
+
let isSend;
|
|
102
|
+
await rateLimiter.middleware(
|
|
103
|
+
req,
|
|
104
|
+
{
|
|
105
|
+
status(statusCode) {
|
|
106
|
+
status = statusCode;
|
|
107
|
+
return this;
|
|
108
|
+
},
|
|
109
|
+
send() {
|
|
110
|
+
isSend = true;
|
|
111
|
+
},
|
|
112
|
+
},
|
|
113
|
+
() => {},
|
|
114
|
+
);
|
|
115
|
+
expect(status).toBe(500);
|
|
116
|
+
expect(isSend).toBe(true);
|
|
117
|
+
});
|
|
118
|
+
|
|
119
|
+
const makeOneRequest = async ({ rateLimiter, driver, request }) => {
|
|
120
|
+
let realRateLimiter = rateLimiter;
|
|
121
|
+
if (!realRateLimiter) {
|
|
122
|
+
realRateLimiter = new RateLimiter(global.server.app, {
|
|
123
|
+
driver,
|
|
124
|
+
});
|
|
125
|
+
}
|
|
126
|
+
const req = {
|
|
127
|
+
appInfo: {},
|
|
128
|
+
...request,
|
|
129
|
+
};
|
|
130
|
+
let status;
|
|
131
|
+
let isSend = false;
|
|
132
|
+
let isNextCalled = false;
|
|
133
|
+
await realRateLimiter.middleware(
|
|
134
|
+
req,
|
|
135
|
+
{
|
|
136
|
+
status(statusCode) {
|
|
137
|
+
status = statusCode;
|
|
138
|
+
return this;
|
|
139
|
+
},
|
|
140
|
+
send() {
|
|
141
|
+
isSend = true;
|
|
142
|
+
},
|
|
143
|
+
},
|
|
144
|
+
() => {
|
|
145
|
+
isNextCalled = true;
|
|
146
|
+
},
|
|
147
|
+
);
|
|
148
|
+
return { status, isSend, isNextCalled };
|
|
149
|
+
};
|
|
150
|
+
|
|
151
|
+
it('middleware should works with a mongo drivers', async () => {
|
|
152
|
+
expect.assertions(1);
|
|
153
|
+
const { isNextCalled } = await makeOneRequest({
|
|
154
|
+
rateLimiter: mongoRateLimiter,
|
|
155
|
+
request: { ip: '10.10.0.1' },
|
|
156
|
+
});
|
|
157
|
+
expect(isNextCalled).toBe(true);
|
|
158
|
+
});
|
|
159
|
+
|
|
160
|
+
it('middleware should works with a memory drivers', async () => {
|
|
161
|
+
expect.assertions(1);
|
|
162
|
+
const { isNextCalled } = await makeOneRequest({
|
|
163
|
+
driver: 'memory',
|
|
164
|
+
request: { ip: '10.10.0.1' },
|
|
165
|
+
});
|
|
166
|
+
expect(isNextCalled).toBe(true);
|
|
167
|
+
});
|
|
168
|
+
|
|
169
|
+
it('middleware should works with a redis drivers', async () => {
|
|
170
|
+
expect.assertions(1);
|
|
171
|
+
const { isNextCalled } = await makeOneRequest({
|
|
172
|
+
driver: 'redis',
|
|
173
|
+
request: { ip: '10.10.0.1' },
|
|
174
|
+
});
|
|
175
|
+
expect(isNextCalled).toBe(true);
|
|
176
|
+
});
|
|
177
|
+
|
|
178
|
+
it('middleware should rate limits for us. mongo driver', async () => {
|
|
179
|
+
expect.assertions(2);
|
|
180
|
+
|
|
181
|
+
const middlewares = Array.from({ length: 20 }, () =>
|
|
182
|
+
makeOneRequest({ rateLimiter: mongoRateLimiter }),
|
|
183
|
+
);
|
|
184
|
+
|
|
185
|
+
const data = await Promise.all(middlewares);
|
|
186
|
+
|
|
187
|
+
const status = data.find((obj) => obj.status === 429);
|
|
188
|
+
const isSend = data.find((obj) => obj.isSend);
|
|
189
|
+
|
|
190
|
+
expect(status.status).toBe(429);
|
|
191
|
+
expect(isSend.isSend).toBe(true);
|
|
192
|
+
});
|
|
193
|
+
|
|
194
|
+
it('middleware should rate limits for us. memory driver', async () => {
|
|
195
|
+
expect.assertions(2);
|
|
196
|
+
|
|
197
|
+
const rateLimiter = new RateLimiter(global.server.app, {
|
|
198
|
+
driver: 'memory',
|
|
199
|
+
});
|
|
200
|
+
|
|
201
|
+
const middlewares = Array.from({ length: 20 }, () =>
|
|
202
|
+
makeOneRequest({ rateLimiter }),
|
|
203
|
+
);
|
|
204
|
+
|
|
205
|
+
const data = await Promise.all(middlewares);
|
|
206
|
+
|
|
207
|
+
const status = data.find((obj) => obj.status === 429);
|
|
208
|
+
const isSend = data.find((obj) => obj.isSend);
|
|
209
|
+
|
|
210
|
+
expect(status.status).toBe(429);
|
|
211
|
+
expect(isSend.isSend).toBe(true);
|
|
212
|
+
});
|
|
213
|
+
|
|
214
|
+
it('middleware should rate limits for us. redis driver', async () => {
|
|
215
|
+
expect.assertions(2);
|
|
216
|
+
|
|
217
|
+
const rateLimiter = new RateLimiter(global.server.app, {
|
|
218
|
+
driver: 'redis',
|
|
219
|
+
});
|
|
220
|
+
|
|
221
|
+
const middlewares = Array.from({ length: 20 }, () =>
|
|
222
|
+
makeOneRequest({ rateLimiter }),
|
|
223
|
+
);
|
|
224
|
+
|
|
225
|
+
const data = await Promise.all(middlewares);
|
|
226
|
+
|
|
227
|
+
const status = data.find((obj) => obj.status === 429);
|
|
228
|
+
const isSend = data.find((obj) => obj.isSend);
|
|
229
|
+
|
|
230
|
+
expect(status.status).toBe(429);
|
|
231
|
+
expect(isSend.isSend).toBe(true);
|
|
232
|
+
});
|
|
50
233
|
});
|
|
@@ -1,7 +1,10 @@
|
|
|
1
|
-
|
|
2
|
-
|
|
1
|
+
import { createServer } from 'node:http';
|
|
2
|
+
import { describe, it, expect } from 'vitest';
|
|
3
|
+
|
|
4
|
+
import RequestParser from './RequestParser';
|
|
3
5
|
|
|
4
|
-
|
|
6
|
+
// TODO change on ESM
|
|
7
|
+
const formidable = require('formidable');
|
|
5
8
|
|
|
6
9
|
describe('reqest parser limiter methods', () => {
|
|
7
10
|
it('have description fields', async () => {
|
|
@@ -24,7 +27,7 @@ describe('reqest parser limiter methods', () => {
|
|
|
24
27
|
expect(req.body.multipleFiles).toBeDefined();
|
|
25
28
|
expect(
|
|
26
29
|
req.body.multipleFiles[0] instanceof formidable.PersistentFile,
|
|
27
|
-
).
|
|
30
|
+
).toBeTruthy();
|
|
28
31
|
|
|
29
32
|
res.writeHead(200);
|
|
30
33
|
res.end('ok');
|
package/tests/setup.js
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
|
+
/* eslint-disable no-undef */
|
|
1
2
|
const path = require('node:path');
|
|
2
|
-
/* eslint-disable jest/require-top-level-describe */
|
|
3
3
|
const { MongoMemoryReplSet } = require('mongodb-memory-server');
|
|
4
4
|
const mongoose = require('mongoose');
|
|
5
5
|
|
|
@@ -14,7 +14,7 @@ jest.setTimeout(1000000);
|
|
|
14
14
|
beforeAll(async () => {
|
|
15
15
|
mongoMemoryServerInstance = await MongoMemoryReplSet.create({
|
|
16
16
|
// binary: { version: '4.4.6' },
|
|
17
|
-
replSet: { storageEngine: 'wiredTiger' },
|
|
17
|
+
replSet: { count: 1, storageEngine: 'wiredTiger' },
|
|
18
18
|
});
|
|
19
19
|
await mongoMemoryServerInstance.waitUntilRunning();
|
|
20
20
|
process.env.LOGGER_CONSOLE_LEVEL = 'error';
|
|
@@ -0,0 +1,119 @@
|
|
|
1
|
+
import path from 'node:path';
|
|
2
|
+
import { beforeAll, beforeEach, afterEach, afterAll } from 'vitest';
|
|
3
|
+
|
|
4
|
+
const { MongoMemoryReplSet } = require('mongodb-memory-server');
|
|
5
|
+
|
|
6
|
+
const mongoose = require('mongoose');
|
|
7
|
+
|
|
8
|
+
let mongoMemoryServerInstance;
|
|
9
|
+
|
|
10
|
+
const redis = require('redis');
|
|
11
|
+
const Server = require('../server');
|
|
12
|
+
|
|
13
|
+
const clearRedisNamespace = require('../helpers/redis/clearNamespace');
|
|
14
|
+
|
|
15
|
+
// eslint-disable-next-line vitest/no-hooks, vitest/require-top-level-describe
|
|
16
|
+
beforeAll(async () => {
|
|
17
|
+
mongoMemoryServerInstance = await MongoMemoryReplSet.create({
|
|
18
|
+
// binary: { version: '4.4.6' },
|
|
19
|
+
replSet: { count: 1, storageEngine: 'wiredTiger' },
|
|
20
|
+
});
|
|
21
|
+
await mongoMemoryServerInstance.waitUntilRunning();
|
|
22
|
+
process.env.LOGGER_CONSOLE_LEVEL = 'error';
|
|
23
|
+
const connectionStringMongo = await mongoMemoryServerInstance.getUri();
|
|
24
|
+
// console.info('MONGO_URI: ', connectionStringMongo);
|
|
25
|
+
global.server = new Server({
|
|
26
|
+
folders: {
|
|
27
|
+
config: process.env.TEST_FOLDER_CONFIG || path.resolve('./config'),
|
|
28
|
+
controllers:
|
|
29
|
+
process.env.TEST_FOLDER_CONTROLLERS || path.resolve('./controllers'),
|
|
30
|
+
views: process.env.TEST_FOLDER_VIEWS || path.resolve('./views'),
|
|
31
|
+
public: process.env.TEST_FOLDER_PUBLIC || path.resolve('./public'),
|
|
32
|
+
models: process.env.TEST_FOLDER_MODELS || path.resolve('./models'),
|
|
33
|
+
emails:
|
|
34
|
+
process.env.TEST_FOLDER_EMAIL ||
|
|
35
|
+
process.env.TEST_FOLDER_EMAILS ||
|
|
36
|
+
path.resolve('./services/messaging/email/templates'),
|
|
37
|
+
locales: process.env.TEST_FOLDER_LOCALES || path.resolve('./locales'),
|
|
38
|
+
commands: process.env.TEST_FOLDER_COMMANDS || path.resolve('./commands'),
|
|
39
|
+
migrations:
|
|
40
|
+
process.env.TEST_FOLDER_MIGRATIONS || path.resolve('./migrations'),
|
|
41
|
+
},
|
|
42
|
+
});
|
|
43
|
+
global.server.updateConfig('mongo', {
|
|
44
|
+
connectionString: connectionStringMongo,
|
|
45
|
+
});
|
|
46
|
+
global.server.updateConfig('http', { port: 0 }); // allow to use random
|
|
47
|
+
global.server.updateConfig('mail', { transport: 'stub' });
|
|
48
|
+
if (!global.testSetup) {
|
|
49
|
+
global.testSetup = {};
|
|
50
|
+
}
|
|
51
|
+
global.server.testingGetUrl = (urlPart) =>
|
|
52
|
+
`http://127.0.0.1:${global.server.getConfig('http').port}${urlPart}`;
|
|
53
|
+
if (!global.testSetup.disableUserCreate) {
|
|
54
|
+
const User = global.server.app.getModel('User');
|
|
55
|
+
global.user = await User.create({
|
|
56
|
+
email: 'test@test.com',
|
|
57
|
+
password: 'testPassword',
|
|
58
|
+
isVerified: true,
|
|
59
|
+
name: {
|
|
60
|
+
nick: 'testUserNickName',
|
|
61
|
+
},
|
|
62
|
+
}).catch((e) => {
|
|
63
|
+
// eslint-disable-next-line no-console
|
|
64
|
+
console.error(e);
|
|
65
|
+
// eslint-disable-next-line no-console
|
|
66
|
+
console.info(
|
|
67
|
+
'That error can happens in case you have custom user model. Please use global.testSetup.disableUserCreate flag to skip user creating',
|
|
68
|
+
);
|
|
69
|
+
});
|
|
70
|
+
global.authToken = await global.user.generateToken();
|
|
71
|
+
}
|
|
72
|
+
if (typeof global.testSetup.beforeAll === 'function') {
|
|
73
|
+
await global.testSetup.beforeAll();
|
|
74
|
+
}
|
|
75
|
+
await global.server.startServer();
|
|
76
|
+
});
|
|
77
|
+
|
|
78
|
+
// eslint-disable-next-line vitest/no-hooks, vitest/require-top-level-describe
|
|
79
|
+
beforeEach(() => {
|
|
80
|
+
if (global.server) {
|
|
81
|
+
const key = `test-${Math.random().toString(36).substring(7)}`;
|
|
82
|
+
global.server.app.updateConfig('redis', {
|
|
83
|
+
namespace: key,
|
|
84
|
+
});
|
|
85
|
+
}
|
|
86
|
+
});
|
|
87
|
+
|
|
88
|
+
// eslint-disable-next-line vitest/no-hooks, vitest/require-top-level-describe
|
|
89
|
+
afterEach(async () => {
|
|
90
|
+
if (global.server) {
|
|
91
|
+
const { url, namespace } = global.server.getConfig('redis');
|
|
92
|
+
const redisClient = redis.createClient({ url });
|
|
93
|
+
|
|
94
|
+
try {
|
|
95
|
+
await redisClient.connect();
|
|
96
|
+
await clearRedisNamespace(redisClient, namespace);
|
|
97
|
+
await redisClient.disconnect();
|
|
98
|
+
} catch (err) {
|
|
99
|
+
// that ok. No redis connection
|
|
100
|
+
}
|
|
101
|
+
}
|
|
102
|
+
});
|
|
103
|
+
|
|
104
|
+
// eslint-disable-next-line vitest/no-hooks, vitest/require-top-level-describe
|
|
105
|
+
afterAll(async () => {
|
|
106
|
+
if (global.server) {
|
|
107
|
+
global.server.app.httpServer.shutdown();
|
|
108
|
+
global.server.app.events.emit('shutdown');
|
|
109
|
+
}
|
|
110
|
+
// setTimeout(async () => {
|
|
111
|
+
if (typeof global.testSetup.afterAll === 'function') {
|
|
112
|
+
await global.testSetup.afterAll();
|
|
113
|
+
}
|
|
114
|
+
|
|
115
|
+
await mongoose.disconnect();
|
|
116
|
+
await mongoMemoryServerInstance.stop();
|
|
117
|
+
|
|
118
|
+
// }, 2000);
|
|
119
|
+
});
|