@adaptivestone/framework 5.0.0-beta.32 → 5.0.0-beta.34
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 +14 -1
- package/dist/services/http/middleware/I18n.d.ts +8 -0
- package/dist/services/http/middleware/I18n.js.map +1 -1
- package/dist/services/http/middleware/RateLimiter.d.ts +8 -1
- package/dist/services/http/middleware/RateLimiter.js +15 -7
- package/dist/services/http/middleware/RateLimiter.js.map +1 -1
- package/package.json +1 -1
package/CHANGELOG.md
CHANGED
|
@@ -48,13 +48,26 @@ Main feature of that release is full TypeScript support insluding mongoose model
|
|
|
48
48
|
- **[BREAKING]** ESM only. No more commonJS. That help to fix a lot of bugs with tests and provides better development expirience.
|
|
49
49
|
- **[BREAKING]** Mongoose v8. <https://mongoosejs.com/docs/migrating_to_8.html>.
|
|
50
50
|
|
|
51
|
+
|
|
52
|
+
|
|
53
|
+
---
|
|
54
|
+
|
|
55
|
+
## [5.0.0-beta.34]
|
|
56
|
+
|
|
57
|
+
- **[NEW]** I18nMiddlewareAppInfo type
|
|
58
|
+
|
|
59
|
+
---
|
|
60
|
+
|
|
61
|
+
## [5.0.0-beta.33]
|
|
62
|
+
|
|
63
|
+
- **[NEW]** consumeResult changed to be more flexible
|
|
64
|
+
|
|
51
65
|
---
|
|
52
66
|
|
|
53
67
|
## [5.0.0-beta.32]
|
|
54
68
|
|
|
55
69
|
- **[NEW]** Ip detector middleware - add getIpAdressFromIncomingMessage function to allow user middleware as a detector of id adresses without middleware
|
|
56
70
|
|
|
57
|
-
|
|
58
71
|
---
|
|
59
72
|
|
|
60
73
|
## [5.0.0-beta.31]
|
|
@@ -8,6 +8,14 @@ export type TI18n = {
|
|
|
8
8
|
t: TFunction;
|
|
9
9
|
language: string;
|
|
10
10
|
};
|
|
11
|
+
export interface I18nMiddlewareAppInfo {
|
|
12
|
+
appInfo: {
|
|
13
|
+
i18n: {
|
|
14
|
+
t: TFunction;
|
|
15
|
+
language: string;
|
|
16
|
+
};
|
|
17
|
+
};
|
|
18
|
+
}
|
|
11
19
|
declare class I18n extends AbstractMiddleware {
|
|
12
20
|
cache: {
|
|
13
21
|
[key: string]: i18n;
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"I18n.js","sourceRoot":"","sources":["../../../../src/services/http/middleware/I18n.ts"],"names":[],"mappings":"AACA,OAAO,OAAO,EAAE,EAA6B,MAAM,SAAS,CAAC;AAC7D,OAAO,SAAS,MAAM,oBAAoB,CAAC;AAI3C,OAAO,kBAAkB,MAAM,yBAAyB,CAAC;
|
|
1
|
+
{"version":3,"file":"I18n.js","sourceRoot":"","sources":["../../../../src/services/http/middleware/I18n.ts"],"names":[],"mappings":"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"}
|
|
@@ -13,7 +13,14 @@ declare class RateLimiter extends AbstractMiddleware {
|
|
|
13
13
|
constructor(app: IApp, params?: Record<string, unknown>);
|
|
14
14
|
initRedisLimiter(): RateLimiterRedis;
|
|
15
15
|
gerenateConsumeKey(req: FrameworkRequest & GetUserByTokenAppInfo): string;
|
|
16
|
-
consumeResult(consumeKey: string): Promise<
|
|
16
|
+
consumeResult(consumeKey: string, consumePoints?: number): Promise<{
|
|
17
|
+
msBeforeNext: number;
|
|
18
|
+
remainingPoints: number;
|
|
19
|
+
consumedPoints: number;
|
|
20
|
+
isFirstInDuration: boolean;
|
|
21
|
+
isAllowed: boolean;
|
|
22
|
+
retryAfter: number;
|
|
23
|
+
}>;
|
|
17
24
|
middleware(req: FrameworkRequest, res: Response, next: NextFunction): Promise<void | Response<any, Record<string, any>>>;
|
|
18
25
|
}
|
|
19
26
|
export default RateLimiter;
|
|
@@ -84,12 +84,17 @@ class RateLimiter extends AbstractMiddleware {
|
|
|
84
84
|
}
|
|
85
85
|
return key.join('_');
|
|
86
86
|
}
|
|
87
|
-
async consumeResult(consumeKey) {
|
|
88
|
-
|
|
89
|
-
.consume(consumeKey, this.finalOptions.consumePoints)
|
|
90
|
-
|
|
87
|
+
async consumeResult(consumeKey, consumePoints = 0) {
|
|
88
|
+
try {
|
|
89
|
+
const result = await this.limiter.consume(consumeKey, consumePoints || this.finalOptions.consumePoints);
|
|
90
|
+
return { isAllowed: true, retryAfter: 0, ...result };
|
|
91
|
+
}
|
|
92
|
+
catch (e) {
|
|
91
93
|
this.logger?.warn(`Too many requests. Consume key: ${consumeKey}`);
|
|
92
|
-
|
|
94
|
+
const result = e;
|
|
95
|
+
const retryAfter = Math.round(result.msBeforeNext / 1000) || 1;
|
|
96
|
+
return { isAllowed: false, retryAfter, ...result };
|
|
97
|
+
}
|
|
93
98
|
}
|
|
94
99
|
async middleware(req, res, next) {
|
|
95
100
|
if (!this.limiter) {
|
|
@@ -99,10 +104,13 @@ class RateLimiter extends AbstractMiddleware {
|
|
|
99
104
|
const { namespace } = this.app.getConfig('redis');
|
|
100
105
|
const consumeKey = `${namespace}-${this.gerenateConsumeKey(req)}`;
|
|
101
106
|
const consumeResult = await this.consumeResult(consumeKey);
|
|
102
|
-
if (consumeResult) {
|
|
107
|
+
if (consumeResult.isAllowed) {
|
|
103
108
|
return next();
|
|
104
109
|
}
|
|
105
|
-
return res
|
|
110
|
+
return res
|
|
111
|
+
.status(429)
|
|
112
|
+
.setHeader('Retry-After', String(consumeResult.retryAfter))
|
|
113
|
+
.json({ message: 'Too Many Requests' });
|
|
106
114
|
}
|
|
107
115
|
}
|
|
108
116
|
export default RateLimiter;
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"RateLimiter.js","sourceRoot":"","sources":["../../../../src/services/http/middleware/RateLimiter.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,YAAY,EAAE,MAAM,eAAe,CAAC;AAC7C,OAAO,KAAK,MAAM,WAAW,CAAC;AAE9B,OAAO,QAAQ,MAAM,UAAU,CAAC;
|
|
1
|
+
{"version":3,"file":"RateLimiter.js","sourceRoot":"","sources":["../../../../src/services/http/middleware/RateLimiter.ts"],"names":[],"mappings":"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"}
|