rate-limiter-flexible 2.3.10 → 2.3.12
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/README.md +4 -4
- package/lib/RateLimiterStoreAbstract.js +92 -34
- package/lib/RateLimiterUnion.js +2 -2
- package/lib/index.d.ts +8 -0
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -29,7 +29,7 @@ Allow **traffic bursts** with [BurstyRateLimiter](https://github.com/animir/node
|
|
|
29
29
|
|
|
30
30
|
**Friendly.** No matter which node package you prefer: `redis` or `ioredis`, `sequelize`/`typeorm` or `knex`, `memcached`, native driver or `mongoose`. It works with all of them.
|
|
31
31
|
|
|
32
|
-
**In memory blocks.** Avoid extra requests to store with [
|
|
32
|
+
**In memory blocks.** Avoid extra requests to store with [inMemoryBlockOnConsumed](https://github.com/animir/node-rate-limiter-flexible/wiki/Options#inmemoryblockonconsumed).
|
|
33
33
|
|
|
34
34
|
**Deno compatible** See [this example](https://gist.github.com/animir/d06ca92931677f330d3f2d4c6c3108e4)
|
|
35
35
|
|
|
@@ -164,8 +164,8 @@ See [releases](https://github.com/animir/node-rate-limiter-flexible/releases) fo
|
|
|
164
164
|
### Other options on Wiki:
|
|
165
165
|
* [keyPrefix](https://github.com/animir/node-rate-limiter-flexible/wiki/Options#keyprefix) Make keys unique among different limiters.
|
|
166
166
|
* [blockDuration](https://github.com/animir/node-rate-limiter-flexible/wiki/Options#blockduration) Block for N seconds, if consumed more than points.
|
|
167
|
-
* [
|
|
168
|
-
* [
|
|
167
|
+
* [inMemoryBlockOnConsumed](https://github.com/animir/node-rate-limiter-flexible/wiki/Options#inmemoryblockonconsumed) Avoid extra requests to store.
|
|
168
|
+
* [inMemoryBlockDuration](https://github.com/animir/node-rate-limiter-flexible/wiki/Options#inmemoryblockduration)
|
|
169
169
|
* [insuranceLimiter](https://github.com/animir/node-rate-limiter-flexible/wiki/Options#insurancelimiter) Make it more stable with less efforts.
|
|
170
170
|
* [storeType](https://github.com/animir/node-rate-limiter-flexible/wiki/Options#storetype) Have to be set to `knex`, if you use it.
|
|
171
171
|
* [dbName](https://github.com/animir/node-rate-limiter-flexible/wiki/Options#dbname) Where to store points.
|
|
@@ -215,7 +215,7 @@ Average latency during test pure NodeJS endpoint in cluster of 4 workers with ev
|
|
|
215
215
|
7. MySQL 14.59 ms (with connection pool 100)
|
|
216
216
|
```
|
|
217
217
|
|
|
218
|
-
Note, you can speed up limiters with [
|
|
218
|
+
Note, you can speed up limiters with [inMemoryBlockOnConsumed](https://github.com/animir/node-rate-limiter-flexible/wiki/Options#inmemoryblockonconsumed) option.
|
|
219
219
|
|
|
220
220
|
## Contribution
|
|
221
221
|
|
|
@@ -8,18 +8,18 @@ module.exports = class RateLimiterStoreAbstract extends RateLimiterAbstract {
|
|
|
8
8
|
* @param opts Object Defaults {
|
|
9
9
|
* ... see other in RateLimiterAbstract
|
|
10
10
|
*
|
|
11
|
-
*
|
|
12
|
-
*
|
|
11
|
+
* inMemoryBlockOnConsumed: 40, // Number of points when key is blocked
|
|
12
|
+
* inMemoryBlockDuration: 10, // Block duration in seconds
|
|
13
13
|
* insuranceLimiter: RateLimiterAbstract
|
|
14
14
|
* }
|
|
15
15
|
*/
|
|
16
16
|
constructor(opts = {}) {
|
|
17
17
|
super(opts);
|
|
18
18
|
|
|
19
|
-
this.
|
|
20
|
-
this.
|
|
19
|
+
this.inMemoryBlockOnConsumed = opts.inMemoryBlockOnConsumed || opts.inmemoryBlockOnConsumed;
|
|
20
|
+
this.inMemoryBlockDuration = opts.inMemoryBlockDuration || opts.inmemoryBlockDuration;
|
|
21
21
|
this.insuranceLimiter = opts.insuranceLimiter;
|
|
22
|
-
this.
|
|
22
|
+
this._inMemoryBlockedKeys = new BlockedKeys();
|
|
23
23
|
}
|
|
24
24
|
|
|
25
25
|
get client() {
|
|
@@ -50,10 +50,10 @@ module.exports = class RateLimiterStoreAbstract extends RateLimiterAbstract {
|
|
|
50
50
|
_afterConsume(resolve, reject, rlKey, changedPoints, storeResult, options = {}) {
|
|
51
51
|
const res = this._getRateLimiterRes(rlKey, changedPoints, storeResult);
|
|
52
52
|
|
|
53
|
-
if (this.
|
|
54
|
-
&& res.consumedPoints >= this.
|
|
53
|
+
if (this.inMemoryBlockOnConsumed > 0 && !(this.inMemoryBlockDuration > 0)
|
|
54
|
+
&& res.consumedPoints >= this.inMemoryBlockOnConsumed
|
|
55
55
|
) {
|
|
56
|
-
this.
|
|
56
|
+
this._inMemoryBlockedKeys.addMs(rlKey, res.msBeforeNext);
|
|
57
57
|
if (res.consumedPoints > this.points) {
|
|
58
58
|
return reject(res);
|
|
59
59
|
} else {
|
|
@@ -67,10 +67,10 @@ module.exports = class RateLimiterStoreAbstract extends RateLimiterAbstract {
|
|
|
67
67
|
blockPromise = this._block(rlKey, res.consumedPoints, this.msBlockDuration, options);
|
|
68
68
|
}
|
|
69
69
|
|
|
70
|
-
if (this.
|
|
71
|
-
// Block key for this.
|
|
72
|
-
this.
|
|
73
|
-
res.msBeforeNext = this.
|
|
70
|
+
if (this.inMemoryBlockOnConsumed > 0 && res.consumedPoints >= this.inMemoryBlockOnConsumed) {
|
|
71
|
+
// Block key for this.inMemoryBlockDuration seconds
|
|
72
|
+
this._inMemoryBlockedKeys.add(rlKey, this.inMemoryBlockDuration);
|
|
73
|
+
res.msBeforeNext = this.msInMemoryBlockDuration;
|
|
74
74
|
}
|
|
75
75
|
|
|
76
76
|
blockPromise
|
|
@@ -106,38 +106,96 @@ module.exports = class RateLimiterStoreAbstract extends RateLimiterAbstract {
|
|
|
106
106
|
}
|
|
107
107
|
}
|
|
108
108
|
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
|
|
109
|
+
/**
|
|
110
|
+
* @deprecated Use camelCase version
|
|
111
|
+
* @returns {BlockedKeys}
|
|
112
|
+
* @private
|
|
113
|
+
*/
|
|
114
|
+
get _inmemoryBlockedKeys() {
|
|
115
|
+
return this._inMemoryBlockedKeys
|
|
116
|
+
}
|
|
113
117
|
|
|
114
|
-
|
|
118
|
+
/**
|
|
119
|
+
* @deprecated Use camelCase version
|
|
120
|
+
* @param rlKey
|
|
121
|
+
* @returns {number}
|
|
122
|
+
*/
|
|
123
|
+
getInmemoryBlockMsBeforeExpire(rlKey) {
|
|
124
|
+
return this.getInMemoryBlockMsBeforeExpire(rlKey)
|
|
115
125
|
}
|
|
116
126
|
|
|
127
|
+
/**
|
|
128
|
+
* @deprecated Use camelCase version
|
|
129
|
+
* @returns {number|number}
|
|
130
|
+
*/
|
|
117
131
|
get inmemoryBlockOnConsumed() {
|
|
118
|
-
return this.
|
|
132
|
+
return this.inMemoryBlockOnConsumed;
|
|
119
133
|
}
|
|
120
134
|
|
|
135
|
+
/**
|
|
136
|
+
* @deprecated Use camelCase version
|
|
137
|
+
* @param value
|
|
138
|
+
*/
|
|
121
139
|
set inmemoryBlockOnConsumed(value) {
|
|
122
|
-
this.
|
|
123
|
-
if (this.inmemoryBlockOnConsumed > 0 && this.points > this.inmemoryBlockOnConsumed) {
|
|
124
|
-
throw new Error('inmemoryBlockOnConsumed option must be greater or equal "points" option');
|
|
125
|
-
}
|
|
140
|
+
this.inMemoryBlockOnConsumed = value;
|
|
126
141
|
}
|
|
127
142
|
|
|
143
|
+
/**
|
|
144
|
+
* @deprecated Use camelCase version
|
|
145
|
+
* @returns {number|number}
|
|
146
|
+
*/
|
|
128
147
|
get inmemoryBlockDuration() {
|
|
129
|
-
return this.
|
|
148
|
+
return this.inMemoryBlockDuration;
|
|
130
149
|
}
|
|
131
150
|
|
|
151
|
+
/**
|
|
152
|
+
* @deprecated Use camelCase version
|
|
153
|
+
* @param value
|
|
154
|
+
*/
|
|
132
155
|
set inmemoryBlockDuration(value) {
|
|
133
|
-
this.
|
|
134
|
-
if (this.inmemoryBlockDuration > 0 && this.inmemoryBlockOnConsumed === 0) {
|
|
135
|
-
throw new Error('inmemoryBlockOnConsumed option must be set up');
|
|
136
|
-
}
|
|
156
|
+
this.inMemoryBlockDuration = value
|
|
137
157
|
}
|
|
138
158
|
|
|
159
|
+
/**
|
|
160
|
+
* @deprecated Use camelCase version
|
|
161
|
+
* @returns {number}
|
|
162
|
+
*/
|
|
139
163
|
get msInmemoryBlockDuration() {
|
|
140
|
-
return this.
|
|
164
|
+
return this.inMemoryBlockDuration * 1000;
|
|
165
|
+
}
|
|
166
|
+
|
|
167
|
+
getInMemoryBlockMsBeforeExpire(rlKey) {
|
|
168
|
+
if (this.inMemoryBlockOnConsumed > 0) {
|
|
169
|
+
return this._inMemoryBlockedKeys.msBeforeExpire(rlKey);
|
|
170
|
+
}
|
|
171
|
+
|
|
172
|
+
return 0;
|
|
173
|
+
}
|
|
174
|
+
|
|
175
|
+
get inMemoryBlockOnConsumed() {
|
|
176
|
+
return this._inMemoryBlockOnConsumed;
|
|
177
|
+
}
|
|
178
|
+
|
|
179
|
+
set inMemoryBlockOnConsumed(value) {
|
|
180
|
+
this._inMemoryBlockOnConsumed = value ? parseInt(value) : 0;
|
|
181
|
+
if (this.inMemoryBlockOnConsumed > 0 && this.points > this.inMemoryBlockOnConsumed) {
|
|
182
|
+
throw new Error('inMemoryBlockOnConsumed option must be greater or equal "points" option');
|
|
183
|
+
}
|
|
184
|
+
}
|
|
185
|
+
|
|
186
|
+
get inMemoryBlockDuration() {
|
|
187
|
+
return this._inMemoryBlockDuration;
|
|
188
|
+
}
|
|
189
|
+
|
|
190
|
+
set inMemoryBlockDuration(value) {
|
|
191
|
+
this._inMemoryBlockDuration = value ? parseInt(value) : 0;
|
|
192
|
+
if (this.inMemoryBlockDuration > 0 && this.inMemoryBlockOnConsumed === 0) {
|
|
193
|
+
throw new Error('inMemoryBlockOnConsumed option must be set up');
|
|
194
|
+
}
|
|
195
|
+
}
|
|
196
|
+
|
|
197
|
+
get msInMemoryBlockDuration() {
|
|
198
|
+
return this._inMemoryBlockDuration * 1000;
|
|
141
199
|
}
|
|
142
200
|
|
|
143
201
|
get insuranceLimiter() {
|
|
@@ -195,9 +253,9 @@ module.exports = class RateLimiterStoreAbstract extends RateLimiterAbstract {
|
|
|
195
253
|
return new Promise((resolve, reject) => {
|
|
196
254
|
const rlKey = this.getKey(key);
|
|
197
255
|
|
|
198
|
-
const
|
|
199
|
-
if (
|
|
200
|
-
return reject(new RateLimiterRes(0,
|
|
256
|
+
const inMemoryBlockMsBeforeExpire = this.getInMemoryBlockMsBeforeExpire(rlKey);
|
|
257
|
+
if (inMemoryBlockMsBeforeExpire > 0) {
|
|
258
|
+
return reject(new RateLimiterRes(0, inMemoryBlockMsBeforeExpire));
|
|
201
259
|
}
|
|
202
260
|
|
|
203
261
|
this._upsert(rlKey, pointsToConsume, this._getKeySecDuration(options) * 1000, false, options)
|
|
@@ -284,7 +342,7 @@ module.exports = class RateLimiterStoreAbstract extends RateLimiterAbstract {
|
|
|
284
342
|
return new Promise((resolve, reject) => {
|
|
285
343
|
this._delete(rlKey, options)
|
|
286
344
|
.then((res) => {
|
|
287
|
-
this.
|
|
345
|
+
this._inMemoryBlockedKeys.delete(rlKey);
|
|
288
346
|
resolve(res);
|
|
289
347
|
})
|
|
290
348
|
.catch((err) => {
|
|
@@ -297,7 +355,7 @@ module.exports = class RateLimiterStoreAbstract extends RateLimiterAbstract {
|
|
|
297
355
|
* Cleanup keys no-matter expired or not.
|
|
298
356
|
*/
|
|
299
357
|
deleteInMemoryBlockedAll() {
|
|
300
|
-
this.
|
|
358
|
+
this._inMemoryBlockedKeys.delete();
|
|
301
359
|
}
|
|
302
360
|
|
|
303
361
|
/**
|
|
@@ -378,7 +436,7 @@ module.exports = class RateLimiterStoreAbstract extends RateLimiterAbstract {
|
|
|
378
436
|
*
|
|
379
437
|
* @return Promise<Object>
|
|
380
438
|
*/
|
|
381
|
-
_upsert() {
|
|
439
|
+
_upsert(rlKey, points, msDuration, forceExpire = false, options = {}) {
|
|
382
440
|
throw new Error("You have to implement the method '_upsert'!");
|
|
383
441
|
}
|
|
384
442
|
};
|
package/lib/RateLimiterUnion.js
CHANGED
|
@@ -2,8 +2,8 @@ const RateLimiterAbstract = require('./RateLimiterAbstract');
|
|
|
2
2
|
|
|
3
3
|
module.exports = class RateLimiterUnion {
|
|
4
4
|
constructor(...limiters) {
|
|
5
|
-
if (limiters.length <
|
|
6
|
-
throw new Error('RateLimiterUnion: at least
|
|
5
|
+
if (limiters.length < 1) {
|
|
6
|
+
throw new Error('RateLimiterUnion: at least one limiter have to be passed');
|
|
7
7
|
}
|
|
8
8
|
limiters.forEach((limiter) => {
|
|
9
9
|
if (!(limiter instanceof RateLimiterAbstract)) {
|
package/lib/index.d.ts
CHANGED
|
@@ -229,7 +229,15 @@ interface IRateLimiterClusterOptions extends IRateLimiterOptions {
|
|
|
229
229
|
interface IRateLimiterStoreOptions extends IRateLimiterOptions {
|
|
230
230
|
storeClient: any;
|
|
231
231
|
storeType?: string;
|
|
232
|
+
inMemoryBlockOnConsumed?: number;
|
|
233
|
+
inMemoryBlockDuration?: number;
|
|
234
|
+
/**
|
|
235
|
+
* @deprecated Use camelCased inMemoryBlockOnConsumed option
|
|
236
|
+
*/
|
|
232
237
|
inmemoryBlockOnConsumed?: number;
|
|
238
|
+
/**
|
|
239
|
+
* @deprecated Use camelCased inMemoryBlockOnConsumed option
|
|
240
|
+
*/
|
|
233
241
|
inmemoryBlockDuration?: number;
|
|
234
242
|
insuranceLimiter?: RateLimiterAbstract;
|
|
235
243
|
dbName?: string;
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "rate-limiter-flexible",
|
|
3
|
-
"version": "2.3.
|
|
3
|
+
"version": "2.3.12",
|
|
4
4
|
"description": "Node.js rate limiter by key and protection from DDoS and Brute-Force attacks in process Memory, Redis, MongoDb, Memcached, MySQL, PostgreSQL, Cluster or PM",
|
|
5
5
|
"main": "index.js",
|
|
6
6
|
"scripts": {
|