@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.
Files changed (87) hide show
  1. package/CHANGELOG.md +10 -0
  2. package/controllers/Auth.test.js +2 -0
  3. package/controllers/Home.test.js +2 -0
  4. package/controllers/index.js +20 -17
  5. package/coverage/base.css +224 -0
  6. package/coverage/block-navigation.js +87 -0
  7. package/coverage/clover.xml +3433 -0
  8. package/coverage/coverage-final.json +41 -0
  9. package/coverage/favicon.png +0 -0
  10. package/coverage/framework/config/auth.js.html +100 -0
  11. package/coverage/framework/config/http.js.html +112 -0
  12. package/coverage/framework/config/i18n.js.html +121 -0
  13. package/coverage/framework/config/index.html +236 -0
  14. package/coverage/framework/config/log.js.html +151 -0
  15. package/coverage/framework/config/mail.js.html +172 -0
  16. package/coverage/framework/config/mongo.js.html +94 -0
  17. package/coverage/framework/config/rateLimiter.js.html +133 -0
  18. package/coverage/framework/config/redis.js.html +97 -0
  19. package/coverage/framework/config/validate.js.html +94 -0
  20. package/coverage/framework/controllers/Auth.js.html +721 -0
  21. package/coverage/framework/controllers/Home.js.html +169 -0
  22. package/coverage/framework/controllers/index.html +146 -0
  23. package/coverage/framework/controllers/index.js.html +268 -0
  24. package/coverage/framework/controllers/test/SomeController.js.html +616 -0
  25. package/coverage/framework/controllers/test/index.html +116 -0
  26. package/coverage/framework/helpers/redis/clearNamespace.js.html +127 -0
  27. package/coverage/framework/helpers/redis/index.html +116 -0
  28. package/coverage/framework/index.html +116 -0
  29. package/coverage/framework/models/Sequence.js.html +151 -0
  30. package/coverage/framework/models/User.js.html +859 -0
  31. package/coverage/framework/models/index.html +131 -0
  32. package/coverage/framework/modules/AbstractController.js.html +1315 -0
  33. package/coverage/framework/modules/AbstractModel.js.html +268 -0
  34. package/coverage/framework/modules/Base.js.html +577 -0
  35. package/coverage/framework/modules/index.html +146 -0
  36. package/coverage/framework/server.js.html +820 -0
  37. package/coverage/framework/services/cache/Cache.js.html +430 -0
  38. package/coverage/framework/services/cache/index.html +116 -0
  39. package/coverage/framework/services/documentation/DocumentationGenerator.js.html +598 -0
  40. package/coverage/framework/services/documentation/index.html +116 -0
  41. package/coverage/framework/services/http/HttpServer.js.html +373 -0
  42. package/coverage/framework/services/http/index.html +116 -0
  43. package/coverage/framework/services/http/middleware/AbstractMiddleware.js.html +238 -0
  44. package/coverage/framework/services/http/middleware/Auth.js.html +145 -0
  45. package/coverage/framework/services/http/middleware/GetUserByToken.js.html +223 -0
  46. package/coverage/framework/services/http/middleware/I18n.js.html +442 -0
  47. package/coverage/framework/services/http/middleware/Pagination.js.html +253 -0
  48. package/coverage/framework/services/http/middleware/PrepareAppInfo.js.html +139 -0
  49. package/coverage/framework/services/http/middleware/RateLimiter.js.html +472 -0
  50. package/coverage/framework/services/http/middleware/RequestLogger.js.html +151 -0
  51. package/coverage/framework/services/http/middleware/RequestParser.js.html +199 -0
  52. package/coverage/framework/services/http/middleware/Role.js.html +172 -0
  53. package/coverage/framework/services/http/middleware/index.html +251 -0
  54. package/coverage/framework/services/http/middleware/test/CheckFlag.js.html +139 -0
  55. package/coverage/framework/services/http/middleware/test/index.html +116 -0
  56. package/coverage/framework/services/messaging/email/index.html +116 -0
  57. package/coverage/framework/services/messaging/email/index.js.html +739 -0
  58. package/coverage/framework/services/messaging/index.html +116 -0
  59. package/coverage/framework/services/messaging/index.js.html +100 -0
  60. package/coverage/framework/services/validate/ValidateService.js.html +568 -0
  61. package/coverage/framework/services/validate/drivers/AbstractValidator.js.html +196 -0
  62. package/coverage/framework/services/validate/drivers/CustomValidator.js.html +241 -0
  63. package/coverage/framework/services/validate/drivers/YupValidator.js.html +394 -0
  64. package/coverage/framework/services/validate/drivers/index.html +146 -0
  65. package/coverage/framework/services/validate/index.html +116 -0
  66. package/coverage/index.html +341 -0
  67. package/coverage/prettify.css +1 -0
  68. package/coverage/prettify.js +2 -0
  69. package/coverage/sort-arrow-sprite.png +0 -0
  70. package/coverage/sorter.js +196 -0
  71. package/models/Sequence.test.js +2 -0
  72. package/models/User.js +8 -8
  73. package/models/User.test.js +2 -0
  74. package/modules/AbstractModel.js +1 -0
  75. package/modules/BaseCli.js +2 -2
  76. package/modules/Modules.test.js +3 -2
  77. package/package.json +7 -18
  78. package/server.js +9 -9
  79. package/services/http/middleware/I18n.test.js +12 -5
  80. package/services/http/middleware/PrepareAppInfo.test.js +7 -3
  81. package/services/http/middleware/RateLimiter.js +5 -6
  82. package/services/http/middleware/RateLimiter.test.js +184 -1
  83. package/services/http/middleware/RequestParser.test.js +7 -4
  84. package/services/validate/ValidateService.test.js +2 -0
  85. package/tests/setup.js +2 -2
  86. package/tests/setupVitest.js +119 -0
  87. package/vitest.config.js +9 -0
@@ -1,6 +1,27 @@
1
- const RateLimiter = require('./RateLimiter');
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
- const { createServer } = require('node:http');
2
- const formidable = require('formidable');
1
+ import { createServer } from 'node:http';
2
+ import { describe, it, expect } from 'vitest';
3
+
4
+ import RequestParser from './RequestParser';
3
5
 
4
- const RequestParser = require('./RequestParser');
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
- ).toBe(true);
30
+ ).toBeTruthy();
28
31
 
29
32
  res.writeHead(200);
30
33
  res.end('ok');
@@ -1,3 +1,5 @@
1
+ import { describe, it, expect } from 'vitest';
2
+
1
3
  const yup = require('yup');
2
4
  const ValidateService = require('./ValidateService');
3
5
  const YupValidator = require('./drivers/YupValidator');
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
+ });
@@ -0,0 +1,9 @@
1
+ // eslint-disable-next-line import/no-unresolved
2
+ import { defineConfig } from 'vitest/config';
3
+
4
+ export default defineConfig({
5
+ test: {
6
+ setupFiles: './tests/setupVitest.js',
7
+ testTimeout: 10000,
8
+ },
9
+ });