@adaptivestone/framework 3.0.20 → 3.0.22

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/.env.example CHANGED
@@ -13,3 +13,6 @@ EMAIL_PASSWORD=""
13
13
  LOGGER_SENTRY_ENABLE=""
14
14
  SENTRY_DSN=
15
15
  LOGGER_CONSOLE_LEVEL=
16
+
17
+ REDIS_NAMESPACE=""
18
+ REDIS_URI=""
package/CHANGELOG.md CHANGED
@@ -1,6 +1,17 @@
1
1
  ### 3.1.0 // NEXT
2
2
 
3
3
  [NEW] new comand to generate open API documentation (wip)
4
+ [NEW] coverage report
5
+
6
+ ### 3.0.22
7
+
8
+ [UPDATE] updated deps
9
+ [UPDATE] cast function now can be ASYNC too
10
+
11
+ ### 3.0.21
12
+
13
+ [UPDATE] updated redis to v4
14
+ [NEW] updates tests to have own namespace on redis
4
15
 
5
16
  ### 3.0.20
6
17
 
@@ -21,7 +21,7 @@ class GetOpenApiJson extends AbstractCommand {
21
21
  {
22
22
  url: myDomain,
23
23
  description: 'Domain from config',
24
- }
24
+ },
25
25
  ],
26
26
  };
27
27
 
package/config/redis.js CHANGED
@@ -1,3 +1,4 @@
1
1
  module.exports = {
2
2
  url: process.env.REDIS_URI || 'redis://localhost',
3
+ namespace: process.env.REDIS_NAMESPACE || 'main',
3
4
  };
@@ -0,0 +1,14 @@
1
+ async function clearNamespace(redisClient, namespace) {
2
+ const deletedKeys = [];
3
+
4
+ const keys = await redisClient.sendCommand(['keys', `*${namespace}*`]);
5
+
6
+ if (keys && keys.length > 0) {
7
+ for (const key of keys) {
8
+ deletedKeys.push(redisClient.sendCommand(['del', key]));
9
+ }
10
+ await Promise.all(deletedKeys);
11
+ }
12
+ }
13
+
14
+ module.exports = clearNamespace;
@@ -110,8 +110,6 @@ class AbstractController extends Base {
110
110
 
111
111
  const middlewaresInfo = parseMiddlewares(this.constructor.middleware);
112
112
  const routesInfo = [];
113
- let routeObjectClone = {};
114
- const routeObjests = [];
115
113
 
116
114
  /**
117
115
  * Register controller middleware
@@ -240,9 +238,12 @@ class AbstractController extends Base {
240
238
  errors: errorAnswer,
241
239
  });
242
240
  }
243
- req.appInfo.request = routeObject.request.cast(bodyAndQuery, {
244
- stripUnknown: true,
245
- });
241
+ req.appInfo.request = await routeObject.request.cast(
242
+ bodyAndQuery,
243
+ {
244
+ stripUnknown: true,
245
+ },
246
+ );
246
247
  }
247
248
  req.body = new Proxy(req.body, {
248
249
  get: (target, prop) => {
@@ -280,8 +281,6 @@ class AbstractController extends Base {
280
281
  });
281
282
  },
282
283
  );
283
-
284
- routeObjectClone = merge({}, routeObject);
285
284
  }
286
285
  }
287
286
 
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@adaptivestone/framework",
3
- "version": "3.0.20",
3
+ "version": "3.0.22",
4
4
  "description": "Adaptive stone node js framework",
5
5
  "main": "src/index.js",
6
6
  "engines": {
@@ -14,7 +14,7 @@
14
14
  "scripts": {
15
15
  "dev": "nodemon ./index.js",
16
16
  "prod": "nodemon ./cluster.js",
17
- "test": "jest",
17
+ "test": "jest --coverage=true",
18
18
  "codestyle": "prettier --check '**/*.(js|jsx|ts|tsx|json|css|scss|md)'",
19
19
  "prepare": "husky install",
20
20
  "cli": "node cliCommand"
@@ -24,7 +24,12 @@
24
24
  "./tests/setup.js"
25
25
  ],
26
26
  "testEnvironment": "node",
27
- "verbose": true
27
+ "verbose": true,
28
+ "collectCoverage": true,
29
+ "coverageReporters": [
30
+ "text",
31
+ "text-summary"
32
+ ]
28
33
  },
29
34
  "author": "Andrey Logunov",
30
35
  "license": "MIT",
@@ -47,7 +52,7 @@
47
52
  "prettier": "^2.3.2",
48
53
  "pug": "^3.0.2",
49
54
  "rate-limiter-flexible": "^2.2.4",
50
- "redis": "^3.1.2",
55
+ "redis": "^4.3.1",
51
56
  "winston": "^3.3.3",
52
57
  "winston-transport-sentry-node": "^2.0.0",
53
58
  "yup": "^0.32.9"
@@ -1,5 +1,4 @@
1
1
  const redis = require('redis');
2
- const { promisify } = require('util');
3
2
  const Base = require('../../modules/Base');
4
3
 
5
4
  class Cache extends Base {
@@ -10,7 +9,12 @@ class Cache extends Base {
10
9
  // we should support multiple cashe same time
11
10
  super(app);
12
11
  const conf = this.app.getConfig('redis');
13
- this.redisClient = redis.createClient(conf.url);
12
+ this.redisClient = redis.createClient({
13
+ url: conf.url,
14
+ });
15
+
16
+ this.redisNamespace = conf.namespace;
17
+
14
18
  this.redisClient.on('error', (error, b, c) => {
15
19
  this.logger.error(error, b, c);
16
20
  });
@@ -20,11 +24,15 @@ class Cache extends Base {
20
24
  this.app.events.on('shutdown', () => {
21
25
  this.redisClient.quit();
22
26
  });
23
- this.redisGetAsync = promisify(this.redisClient.get).bind(this.redisClient);
27
+
24
28
  this.promiseMapping = new Map();
25
29
  }
26
30
 
27
- async getSetValue(key, onNotFound, storeTime = 60 * 5) {
31
+ async getSetValue(keyValue, onNotFound, storeTime = 60 * 5) {
32
+ if (!this.redisClient.isOpen) {
33
+ await this.redisClient.connect();
34
+ }
35
+ const key = `${this.redisNamespace}-${keyValue}`;
28
36
  // 5 mins default
29
37
  let resolve = null;
30
38
  if (this.promiseMapping.has(key)) {
@@ -38,11 +46,11 @@ class Cache extends Base {
38
46
  }),
39
47
  );
40
48
 
41
- let result = await this.redisGetAsync(key);
49
+ let result = await this.redisClient.get(key);
42
50
  if (!result) {
43
51
  this.logger.verbose(`getSetValueFromCache not found for key ${key}`);
44
52
  result = await onNotFound();
45
- this.redisClient.set(key, JSON.stringify(result), 'EX', storeTime);
53
+ this.redisClient.setEx(key, storeTime, JSON.stringify(result));
46
54
  } else {
47
55
  this.logger.verbose(
48
56
  `getSetValueFromCache FROM CACHE key ${key}, value ${result}`,
@@ -16,9 +16,10 @@ class RateLimiter extends AbstractMiddleware {
16
16
 
17
17
  constructor(app, params) {
18
18
  super(app, params);
19
+ const routeParams = params;
19
20
  const limiterOptions = this.app.getConfig('rateLimiter');
20
- this.finalOptions = merge(limiterOptions, params);
21
21
 
22
+ this.finalOptions = merge(limiterOptions, routeParams);
22
23
  this.limiter = null;
23
24
 
24
25
  switch (this.finalOptions.driver) {
@@ -47,7 +48,16 @@ class RateLimiter extends AbstractMiddleware {
47
48
 
48
49
  initRedisLimiter() {
49
50
  const redisConfig = this.app.getConfig('redis');
50
- const redisClient = redis.createClient(redisConfig.url);
51
+ const redisClient = redis.createClient({
52
+ url: redisConfig.url,
53
+ legacyMode: true,
54
+ });
55
+
56
+ // TODO: change it
57
+ (async () => {
58
+ await redisClient.connect();
59
+ })();
60
+
51
61
  redisClient.on('error', (error, b, c) => {
52
62
  this.logger.error(error, b, c);
53
63
  });
@@ -55,8 +65,8 @@ class RateLimiter extends AbstractMiddleware {
55
65
  this.logger.info('Redis connection success');
56
66
  });
57
67
 
58
- this.app.events.on('shutdown', () => {
59
- redisClient.quit();
68
+ this.app.events.on('shutdown', async () => {
69
+ await redisClient.disconnect();
60
70
  });
61
71
 
62
72
  return new RateLimiterRedis({
@@ -100,7 +110,9 @@ class RateLimiter extends AbstractMiddleware {
100
110
  );
101
111
  }
102
112
 
103
- const consumeKey = this.gerenateConsumeKey(req);
113
+ const { namespace } = this.app.getConfig('redis');
114
+
115
+ const consumeKey = `${namespace}-${this.gerenateConsumeKey(req)}`;
104
116
 
105
117
  const consumeResult = await this.limiter
106
118
  .consume(consumeKey, this.finalOptions.consumePoints)
package/tests/setup.js CHANGED
@@ -4,8 +4,11 @@ const mongoose = require('mongoose');
4
4
 
5
5
  let mongoMemoryServerInstance;
6
6
  const path = require('path');
7
+ const redis = require('redis');
7
8
  const Server = require('../server');
8
9
 
10
+ const clearRadisNamespace = require('../helpers/redis/clearNamespace');
11
+
9
12
  jest.setTimeout(1000000);
10
13
  beforeAll(async () => {
11
14
  mongoMemoryServerInstance = await MongoMemoryReplSet.create({
@@ -63,6 +66,27 @@ beforeAll(async () => {
63
66
  }
64
67
  await global.server.startServer();
65
68
  });
69
+
70
+ beforeEach(() => {
71
+ if (global.server) {
72
+ const key = `test-${Math.random().toString(36).substring(7)}`;
73
+ global.server.app.updateConfig('redis', {
74
+ namespace: key,
75
+ });
76
+ }
77
+ });
78
+
79
+ afterEach(async () => {
80
+ if (global.server) {
81
+ const { url, namespace } = global.server.getConfig('redis');
82
+ const redisClient = redis.createClient({ url });
83
+
84
+ await redisClient.connect();
85
+ await clearRadisNamespace(redisClient, namespace);
86
+ await redisClient.disconnect();
87
+ }
88
+ });
89
+
66
90
  afterAll(async () => {
67
91
  if (global.server) {
68
92
  global.server.app.httpServer.shutdown();
@@ -72,7 +96,9 @@ afterAll(async () => {
72
96
  if (typeof global.testSetup.afterAll === 'function') {
73
97
  await global.testSetup.afterAll();
74
98
  }
99
+
75
100
  await mongoose.disconnect();
76
101
  await mongoMemoryServerInstance.stop();
102
+
77
103
  // }, 2000);
78
104
  });