rate-limiter-flexible 8.0.1 → 8.2.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/README.md +3 -2
- package/lib/RLWrapperTimeouts.js +82 -0
- package/lib/RateLimiterInsuredAbstract.js +109 -0
- package/lib/RateLimiterRedis.js +29 -8
- package/lib/RateLimiterStoreAbstract.js +11 -46
- package/package.json +1 -1
- package/types.d.ts +15 -1
package/README.md
CHANGED
|
@@ -10,7 +10,7 @@
|
|
|
10
10
|
|
|
11
11
|
## node-rate-limiter-flexible
|
|
12
12
|
|
|
13
|
-
**rate-limiter-flexible** counts and limits the number of actions by key and protects from
|
|
13
|
+
**rate-limiter-flexible** counts and limits the number of actions by key and protects from DoS and brute force attacks at any scale.
|
|
14
14
|
|
|
15
15
|
It works with _Valkey_, _Redis_, _Prisma_, _DynamoDB_, process _Memory_, _Cluster_ or _PM2_, _Memcached_, _MongoDB_, _MySQL_, _SQLite_, and _PostgreSQL_.
|
|
16
16
|
|
|
@@ -96,7 +96,7 @@ const headers = {
|
|
|
96
96
|
* no race conditions
|
|
97
97
|
* no production dependencies
|
|
98
98
|
* TypeScript declaration bundled
|
|
99
|
-
* Block Strategy against really powerful
|
|
99
|
+
* Block Strategy against really powerful DoS attacks (like 100k requests per sec) [Read about it and benchmarking here](https://github.com/animir/node-rate-limiter-flexible/wiki/In-memory-Block-Strategy)
|
|
100
100
|
* Insurance Strategy as emergency solution if database/store is down [Read about Insurance Strategy here](https://github.com/animir/node-rate-limiter-flexible/wiki/Insurance-Strategy)
|
|
101
101
|
* works in Cluster or PM2 without additional software [See RateLimiterCluster benchmark and detailed description here](https://github.com/animir/node-rate-limiter-flexible/wiki/Cluster)
|
|
102
102
|
* useful `get`, `set`, `block`, `delete`, `penalty` and `reward` methods
|
|
@@ -147,6 +147,7 @@ Some copy/paste examples on Wiki:
|
|
|
147
147
|
* [BurstyRateLimiter](https://github.com/animir/node-rate-limiter-flexible/wiki/BurstyRateLimiter) Traffic burst support
|
|
148
148
|
* [RateLimiterUnion](https://github.com/animir/node-rate-limiter-flexible/wiki/RateLimiterUnion) Combine 2 or more limiters to act as single
|
|
149
149
|
* [RLWrapperBlackAndWhite](https://github.com/animir/node-rate-limiter-flexible/wiki/Black-and-White-lists) Black and White lists
|
|
150
|
+
* [RLWrapperTimeouts](https://github.com/animir/node-rate-limiter-flexible/wiki/RLWrapperTimeouts) Timeouts
|
|
150
151
|
* [RateLimiterQueue](https://github.com/animir/node-rate-limiter-flexible/wiki/RateLimiterQueue) Rate limiter with FIFO queue
|
|
151
152
|
* [AWS SDK v3 Client Rate Limiter](https://github.com/animir/node-rate-limiter-flexible/wiki/AWS-SDK-v3-Client-Rate-Limiter) Prevent punishing rate limit.
|
|
152
153
|
|
|
@@ -0,0 +1,82 @@
|
|
|
1
|
+
const RateLimiterAbstract = require('./RateLimiterAbstract');
|
|
2
|
+
const RateLimiterInsuredAbstract = require('./RateLimiterInsuredAbstract');
|
|
3
|
+
|
|
4
|
+
module.exports = class RLWrapperTimeouts extends RateLimiterInsuredAbstract {
|
|
5
|
+
constructor(opts= {}) {
|
|
6
|
+
super(opts);
|
|
7
|
+
this.limiter = opts.limiter;
|
|
8
|
+
this.timeoutMs = opts.timeoutMs || 0;
|
|
9
|
+
}
|
|
10
|
+
|
|
11
|
+
get limiter() {
|
|
12
|
+
return this._limiter;
|
|
13
|
+
}
|
|
14
|
+
|
|
15
|
+
set limiter(limiter) {
|
|
16
|
+
if (!(limiter instanceof RateLimiterAbstract)) {
|
|
17
|
+
throw new TypeError('limiter must be an instance of RateLimiterAbstract');
|
|
18
|
+
}
|
|
19
|
+
this._limiter = limiter;
|
|
20
|
+
if (!this.insuranceLimiter && limiter instanceof RateLimiterInsuredAbstract) {
|
|
21
|
+
this.insuranceLimiter = limiter.insuranceLimiter;
|
|
22
|
+
}
|
|
23
|
+
}
|
|
24
|
+
|
|
25
|
+
get timeoutMs() {
|
|
26
|
+
return this._timeoutMs;
|
|
27
|
+
}
|
|
28
|
+
|
|
29
|
+
set timeoutMs(value) {
|
|
30
|
+
if (typeof value !== 'number' || value < 0) {
|
|
31
|
+
throw new TypeError('timeoutMs must be a non-negative number');
|
|
32
|
+
}
|
|
33
|
+
this._timeoutMs = value;
|
|
34
|
+
}
|
|
35
|
+
|
|
36
|
+
_run(funcName, params) {
|
|
37
|
+
return new Promise(async (resolve, reject) => {
|
|
38
|
+
const timeout = setTimeout(() => {
|
|
39
|
+
return reject(new Error('Operation timed out'));
|
|
40
|
+
}, this.timeoutMs);
|
|
41
|
+
|
|
42
|
+
await this.limiter[funcName](...params)
|
|
43
|
+
.then((result) => {
|
|
44
|
+
clearTimeout(timeout);
|
|
45
|
+
resolve(result);
|
|
46
|
+
})
|
|
47
|
+
.catch((err) => {
|
|
48
|
+
clearTimeout(timeout);
|
|
49
|
+
reject(err);
|
|
50
|
+
});
|
|
51
|
+
});
|
|
52
|
+
}
|
|
53
|
+
|
|
54
|
+
_consume(key, pointsToConsume = 1, options = {}) {
|
|
55
|
+
return this._run('consume', [key, pointsToConsume, options]);
|
|
56
|
+
}
|
|
57
|
+
|
|
58
|
+
_penalty(key, points = 1, options = {}) {
|
|
59
|
+
return this._run('penalty', [key, points, options]);
|
|
60
|
+
}
|
|
61
|
+
|
|
62
|
+
_reward(key, points = 1, options = {}) {
|
|
63
|
+
return this._run('reward', [key, points, options]);
|
|
64
|
+
}
|
|
65
|
+
|
|
66
|
+
_get(key, options = {}) {
|
|
67
|
+
return this._run('get', [key, options]);
|
|
68
|
+
}
|
|
69
|
+
|
|
70
|
+
_set(key, points, secDuration, options = {}) {
|
|
71
|
+
return this._run('set', [key, points, secDuration, options]);
|
|
72
|
+
}
|
|
73
|
+
|
|
74
|
+
_block(key, secDuration, options = {}) {
|
|
75
|
+
return this._run('block', [key, secDuration, options]);
|
|
76
|
+
}
|
|
77
|
+
|
|
78
|
+
_delete(key, options = {}) {
|
|
79
|
+
return this._run('delete', [key, options]);
|
|
80
|
+
}
|
|
81
|
+
|
|
82
|
+
}
|
|
@@ -0,0 +1,109 @@
|
|
|
1
|
+
const RateLimiterAbstract = require('./RateLimiterAbstract');
|
|
2
|
+
|
|
3
|
+
module.exports = class RateLimiterInsuredAbstract extends RateLimiterAbstract {
|
|
4
|
+
constructor(opts = {}) {
|
|
5
|
+
super(opts);
|
|
6
|
+
this.insuranceLimiter = opts.insuranceLimiter;
|
|
7
|
+
}
|
|
8
|
+
|
|
9
|
+
get insuranceLimiter() {
|
|
10
|
+
return this._insuranceLimiter;
|
|
11
|
+
}
|
|
12
|
+
|
|
13
|
+
set insuranceLimiter(value) {
|
|
14
|
+
if (typeof value !== 'undefined' && !(value instanceof RateLimiterAbstract)) {
|
|
15
|
+
throw new Error('insuranceLimiter must be instance of RateLimiterAbstract');
|
|
16
|
+
}
|
|
17
|
+
this._insuranceLimiter = value;
|
|
18
|
+
if (this._insuranceLimiter) {
|
|
19
|
+
this._insuranceLimiter.blockDuration = this.blockDuration;
|
|
20
|
+
this._insuranceLimiter.execEvenly = this.execEvenly;
|
|
21
|
+
}
|
|
22
|
+
}
|
|
23
|
+
|
|
24
|
+
_handleError(err, funcName, resolve, reject, params) {
|
|
25
|
+
if (!(this.insuranceLimiter instanceof RateLimiterAbstract)) {
|
|
26
|
+
reject(err);
|
|
27
|
+
} else {
|
|
28
|
+
this.insuranceLimiter[funcName](...params)
|
|
29
|
+
.then((res) => {
|
|
30
|
+
resolve(res);
|
|
31
|
+
})
|
|
32
|
+
.catch((res) => {
|
|
33
|
+
reject(res);
|
|
34
|
+
});
|
|
35
|
+
}
|
|
36
|
+
}
|
|
37
|
+
|
|
38
|
+
_operation(funcName, params) {
|
|
39
|
+
const promise = this[funcName](...params);
|
|
40
|
+
return new Promise((resolve, reject) => {
|
|
41
|
+
return promise.then((res) => {
|
|
42
|
+
resolve(res);
|
|
43
|
+
})
|
|
44
|
+
.catch((err) => {
|
|
45
|
+
if (funcName.startsWith('_')) {
|
|
46
|
+
funcName = funcName.slice(1);
|
|
47
|
+
}
|
|
48
|
+
this._handleError(err, funcName, resolve, reject, params);
|
|
49
|
+
});
|
|
50
|
+
});
|
|
51
|
+
}
|
|
52
|
+
|
|
53
|
+
consume(key, pointsToConsume = 1, options = {}) {
|
|
54
|
+
return this._operation('_consume', [key, pointsToConsume, options]);
|
|
55
|
+
}
|
|
56
|
+
|
|
57
|
+
penalty(key, points = 1, options = {}) {
|
|
58
|
+
return this._operation('_penalty', [key, points, options]);
|
|
59
|
+
}
|
|
60
|
+
|
|
61
|
+
reward(key, points = 1, options = {}) {
|
|
62
|
+
return this._operation('_reward', [key, points, options]);
|
|
63
|
+
}
|
|
64
|
+
|
|
65
|
+
get(key, options = {}) {
|
|
66
|
+
return this._operation('_get', [key, options]);
|
|
67
|
+
}
|
|
68
|
+
|
|
69
|
+
set(key, points, secDuration, options = {}) {
|
|
70
|
+
return this._operation('_set', [key, points, secDuration, options]);
|
|
71
|
+
}
|
|
72
|
+
|
|
73
|
+
block(key, secDuration, options = {}) {
|
|
74
|
+
return this._operation('_block', [key, secDuration, options]);
|
|
75
|
+
}
|
|
76
|
+
|
|
77
|
+
delete(key, options = {}) {
|
|
78
|
+
return this._operation('_delete', [key, options]);
|
|
79
|
+
}
|
|
80
|
+
|
|
81
|
+
_consume() {
|
|
82
|
+
throw new Error("You have to implement the method '_consume'!");
|
|
83
|
+
}
|
|
84
|
+
|
|
85
|
+
_penalty() {
|
|
86
|
+
throw new Error("You have to implement the method '_penalty'!");
|
|
87
|
+
}
|
|
88
|
+
|
|
89
|
+
_reward() {
|
|
90
|
+
throw new Error("You have to implement the method '_reward'!");
|
|
91
|
+
}
|
|
92
|
+
|
|
93
|
+
_get() {
|
|
94
|
+
throw new Error("You have to implement the method '_get'!");
|
|
95
|
+
}
|
|
96
|
+
|
|
97
|
+
_set() {
|
|
98
|
+
throw new Error("You have to implement the method '_set'!");
|
|
99
|
+
}
|
|
100
|
+
|
|
101
|
+
_block() {
|
|
102
|
+
throw new Error("You have to implement the method '_block'!");
|
|
103
|
+
}
|
|
104
|
+
|
|
105
|
+
_delete() {
|
|
106
|
+
throw new Error("You have to implement the method '_delete'!");
|
|
107
|
+
}
|
|
108
|
+
|
|
109
|
+
}
|
package/lib/RateLimiterRedis.js
CHANGED
|
@@ -43,20 +43,41 @@ class RateLimiterRedis extends RateLimiterStoreAbstract {
|
|
|
43
43
|
* Prevent actual redis call if redis connection is not ready
|
|
44
44
|
* Because of different connection state checks for ioredis and node-redis, only this clients would be actually checked.
|
|
45
45
|
* For any other clients all the requests would be passed directly to redis client
|
|
46
|
+
* @param {String} rlKey
|
|
47
|
+
* @param {Boolean} isReadonly
|
|
46
48
|
* @return {boolean}
|
|
47
49
|
* @private
|
|
48
50
|
*/
|
|
49
|
-
_isRedisReady() {
|
|
51
|
+
_isRedisReady(rlKey, isReadonly) {
|
|
50
52
|
if (!this._rejectIfRedisNotReady) {
|
|
51
53
|
return true;
|
|
52
54
|
}
|
|
53
55
|
// ioredis client
|
|
54
|
-
if (this.client.status
|
|
55
|
-
return
|
|
56
|
+
if (this.client.status) {
|
|
57
|
+
return this.client.status === 'ready';
|
|
56
58
|
}
|
|
57
|
-
// node-redis client
|
|
58
|
-
if (typeof this.client.isReady === 'function'
|
|
59
|
-
return
|
|
59
|
+
// node-redis v3 client
|
|
60
|
+
if (typeof this.client.isReady === 'function') {
|
|
61
|
+
return this.client.isReady();
|
|
62
|
+
}
|
|
63
|
+
|
|
64
|
+
// node-redis v4+ (non-cluster) client
|
|
65
|
+
if (typeof this.client.isReady === 'boolean') {
|
|
66
|
+
return this.client.isReady === true;
|
|
67
|
+
}
|
|
68
|
+
|
|
69
|
+
// node-redis v4+ cluster client
|
|
70
|
+
if (this.client._slots && typeof this.client._slots.getClient === 'function') {
|
|
71
|
+
if (typeof this.client.isOpen === 'boolean' && this.client.isOpen !== true) {
|
|
72
|
+
return false;
|
|
73
|
+
}
|
|
74
|
+
|
|
75
|
+
try {
|
|
76
|
+
const slotClient = this.client._slots.getClient(rlKey, isReadonly);
|
|
77
|
+
return slotClient && slotClient.isReady === true;
|
|
78
|
+
} catch (error) {
|
|
79
|
+
return false;
|
|
80
|
+
}
|
|
60
81
|
}
|
|
61
82
|
return true;
|
|
62
83
|
}
|
|
@@ -89,7 +110,7 @@ class RateLimiterRedis extends RateLimiterStoreAbstract {
|
|
|
89
110
|
throw new Error("Consuming decimal number of points is not supported by this package");
|
|
90
111
|
}
|
|
91
112
|
|
|
92
|
-
if (!this._isRedisReady()) {
|
|
113
|
+
if (!this._isRedisReady(rlKey, false)) {
|
|
93
114
|
throw new Error('Redis connection is not ready');
|
|
94
115
|
}
|
|
95
116
|
|
|
@@ -150,7 +171,7 @@ class RateLimiterRedis extends RateLimiterStoreAbstract {
|
|
|
150
171
|
}
|
|
151
172
|
|
|
152
173
|
async _get(rlKey) {
|
|
153
|
-
if (!this._isRedisReady()) {
|
|
174
|
+
if (!this._isRedisReady(rlKey, true)) {
|
|
154
175
|
throw new Error('Redis connection is not ready');
|
|
155
176
|
}
|
|
156
177
|
if(!this.useRedisPackage && !this.useRedis3AndLowerPackage){
|
|
@@ -1,8 +1,9 @@
|
|
|
1
1
|
const RateLimiterAbstract = require('./RateLimiterAbstract');
|
|
2
2
|
const BlockedKeys = require('./component/BlockedKeys');
|
|
3
3
|
const RateLimiterRes = require('./RateLimiterRes');
|
|
4
|
+
const RateLimiterInsuredAbstract = require('./RateLimiterInsuredAbstract');
|
|
4
5
|
|
|
5
|
-
module.exports = class RateLimiterStoreAbstract extends
|
|
6
|
+
module.exports = class RateLimiterStoreAbstract extends RateLimiterInsuredAbstract {
|
|
6
7
|
/**
|
|
7
8
|
*
|
|
8
9
|
* @param opts Object Defaults {
|
|
@@ -18,7 +19,6 @@ module.exports = class RateLimiterStoreAbstract extends RateLimiterAbstract {
|
|
|
18
19
|
|
|
19
20
|
this.inMemoryBlockOnConsumed = opts.inMemoryBlockOnConsumed;
|
|
20
21
|
this.inMemoryBlockDuration = opts.inMemoryBlockDuration;
|
|
21
|
-
this.insuranceLimiter = opts.insuranceLimiter;
|
|
22
22
|
this._inMemoryBlockedKeys = new BlockedKeys();
|
|
23
23
|
}
|
|
24
24
|
|
|
@@ -92,20 +92,6 @@ module.exports = class RateLimiterStoreAbstract extends RateLimiterAbstract {
|
|
|
92
92
|
}
|
|
93
93
|
}
|
|
94
94
|
|
|
95
|
-
_handleError(err, funcName, resolve, reject, key, data = false, options = {}) {
|
|
96
|
-
if (!(this.insuranceLimiter instanceof RateLimiterAbstract)) {
|
|
97
|
-
reject(err);
|
|
98
|
-
} else {
|
|
99
|
-
this.insuranceLimiter[funcName](key, data, options)
|
|
100
|
-
.then((res) => {
|
|
101
|
-
resolve(res);
|
|
102
|
-
})
|
|
103
|
-
.catch((res) => {
|
|
104
|
-
reject(res);
|
|
105
|
-
});
|
|
106
|
-
}
|
|
107
|
-
}
|
|
108
|
-
|
|
109
95
|
getInMemoryBlockMsBeforeExpire(rlKey) {
|
|
110
96
|
if (this.inMemoryBlockOnConsumed > 0) {
|
|
111
97
|
return this._inMemoryBlockedKeys.msBeforeExpire(rlKey);
|
|
@@ -140,21 +126,6 @@ module.exports = class RateLimiterStoreAbstract extends RateLimiterAbstract {
|
|
|
140
126
|
return this._inMemoryBlockDuration * 1000;
|
|
141
127
|
}
|
|
142
128
|
|
|
143
|
-
get insuranceLimiter() {
|
|
144
|
-
return this._insuranceLimiter;
|
|
145
|
-
}
|
|
146
|
-
|
|
147
|
-
set insuranceLimiter(value) {
|
|
148
|
-
if (typeof value !== 'undefined' && !(value instanceof RateLimiterAbstract)) {
|
|
149
|
-
throw new Error('insuranceLimiter must be instance of RateLimiterAbstract');
|
|
150
|
-
}
|
|
151
|
-
this._insuranceLimiter = value;
|
|
152
|
-
if (this._insuranceLimiter) {
|
|
153
|
-
this._insuranceLimiter.blockDuration = this.blockDuration;
|
|
154
|
-
this._insuranceLimiter.execEvenly = this.execEvenly;
|
|
155
|
-
}
|
|
156
|
-
}
|
|
157
|
-
|
|
158
129
|
/**
|
|
159
130
|
* Block any key for secDuration seconds
|
|
160
131
|
*
|
|
@@ -191,7 +162,7 @@ module.exports = class RateLimiterStoreAbstract extends RateLimiterAbstract {
|
|
|
191
162
|
* @param {Object} options
|
|
192
163
|
* @returns Promise<RateLimiterRes>
|
|
193
164
|
*/
|
|
194
|
-
|
|
165
|
+
_consume(key, pointsToConsume = 1, options = {}) {
|
|
195
166
|
return new Promise((resolve, reject) => {
|
|
196
167
|
const rlKey = this.getKey(key);
|
|
197
168
|
|
|
@@ -204,9 +175,7 @@ module.exports = class RateLimiterStoreAbstract extends RateLimiterAbstract {
|
|
|
204
175
|
.then((res) => {
|
|
205
176
|
this._afterConsume(resolve, reject, rlKey, pointsToConsume, res);
|
|
206
177
|
})
|
|
207
|
-
.catch((err) =>
|
|
208
|
-
this._handleError(err, 'consume', resolve, reject, key, pointsToConsume, options);
|
|
209
|
-
});
|
|
178
|
+
.catch((err) => reject(err));
|
|
210
179
|
});
|
|
211
180
|
}
|
|
212
181
|
|
|
@@ -217,16 +186,14 @@ module.exports = class RateLimiterStoreAbstract extends RateLimiterAbstract {
|
|
|
217
186
|
* @param {Object} options
|
|
218
187
|
* @returns Promise<RateLimiterRes>
|
|
219
188
|
*/
|
|
220
|
-
|
|
189
|
+
_penalty(key, points = 1, options = {}) {
|
|
221
190
|
const rlKey = this.getKey(key);
|
|
222
191
|
return new Promise((resolve, reject) => {
|
|
223
192
|
this._upsert(rlKey, points, this._getKeySecDuration(options) * 1000, false, options)
|
|
224
193
|
.then((res) => {
|
|
225
194
|
resolve(this._getRateLimiterRes(rlKey, points, res));
|
|
226
195
|
})
|
|
227
|
-
.catch((
|
|
228
|
-
this._handleError(err, 'penalty', resolve, reject, key, points, options);
|
|
229
|
-
});
|
|
196
|
+
.catch((res) => reject(res));
|
|
230
197
|
});
|
|
231
198
|
}
|
|
232
199
|
|
|
@@ -237,16 +204,14 @@ module.exports = class RateLimiterStoreAbstract extends RateLimiterAbstract {
|
|
|
237
204
|
* @param {Object} options
|
|
238
205
|
* @returns Promise<RateLimiterRes>
|
|
239
206
|
*/
|
|
240
|
-
|
|
207
|
+
_reward(key, points = 1, options = {}) {
|
|
241
208
|
const rlKey = this.getKey(key);
|
|
242
209
|
return new Promise((resolve, reject) => {
|
|
243
210
|
this._upsert(rlKey, -points, this._getKeySecDuration(options) * 1000, false, options)
|
|
244
211
|
.then((res) => {
|
|
245
212
|
resolve(this._getRateLimiterRes(rlKey, -points, res));
|
|
246
213
|
})
|
|
247
|
-
.catch((
|
|
248
|
-
this._handleError(err, 'reward', resolve, reject, key, points, options);
|
|
249
|
-
});
|
|
214
|
+
.catch((res) => reject(res));
|
|
250
215
|
});
|
|
251
216
|
}
|
|
252
217
|
|
|
@@ -268,7 +233,7 @@ module.exports = class RateLimiterStoreAbstract extends RateLimiterAbstract {
|
|
|
268
233
|
}
|
|
269
234
|
})
|
|
270
235
|
.catch((err) => {
|
|
271
|
-
this._handleError(err, 'get', resolve, reject, key, options);
|
|
236
|
+
this._handleError(err, 'get', resolve, reject, [key, options]);
|
|
272
237
|
});
|
|
273
238
|
});
|
|
274
239
|
}
|
|
@@ -288,7 +253,7 @@ module.exports = class RateLimiterStoreAbstract extends RateLimiterAbstract {
|
|
|
288
253
|
resolve(res);
|
|
289
254
|
})
|
|
290
255
|
.catch((err) => {
|
|
291
|
-
this._handleError(err, 'delete', resolve, reject, key, options);
|
|
256
|
+
this._handleError(err, 'delete', resolve, reject, [key, options]);
|
|
292
257
|
});
|
|
293
258
|
});
|
|
294
259
|
}
|
|
@@ -330,7 +295,7 @@ module.exports = class RateLimiterStoreAbstract extends RateLimiterAbstract {
|
|
|
330
295
|
resolve(new RateLimiterRes(0, msDuration > 0 ? msDuration : -1, initPoints));
|
|
331
296
|
})
|
|
332
297
|
.catch((err) => {
|
|
333
|
-
this._handleError(err, 'block', resolve, reject, this.parseKey(rlKey), msDuration / 1000, options);
|
|
298
|
+
this._handleError(err, 'block', resolve, reject, [this.parseKey(rlKey), msDuration / 1000, options]);
|
|
334
299
|
});
|
|
335
300
|
});
|
|
336
301
|
}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "rate-limiter-flexible",
|
|
3
|
-
"version": "8.0
|
|
3
|
+
"version": "8.2.0",
|
|
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": {
|
package/types.d.ts
CHANGED
|
@@ -204,7 +204,11 @@ export class RateLimiterAbstract {
|
|
|
204
204
|
): Promise<boolean>;
|
|
205
205
|
}
|
|
206
206
|
|
|
207
|
-
export class
|
|
207
|
+
export class RateLimiterInsuredAbstract extends RateLimiterAbstract {
|
|
208
|
+
constructor(opts: IRateLimiterOptions);
|
|
209
|
+
}
|
|
210
|
+
|
|
211
|
+
export class RateLimiterStoreAbstract extends RateLimiterInsuredAbstract {
|
|
208
212
|
constructor(opts: IRateLimiterStoreOptions);
|
|
209
213
|
|
|
210
214
|
/**
|
|
@@ -220,6 +224,7 @@ interface IRateLimiterOptions {
|
|
|
220
224
|
execEvenly?: boolean;
|
|
221
225
|
execEvenlyMinDelayMs?: number;
|
|
222
226
|
blockDuration?: number;
|
|
227
|
+
insuranceLimiter?: RateLimiterAbstract;
|
|
223
228
|
}
|
|
224
229
|
|
|
225
230
|
interface IRateLimiterClusterOptions extends IRateLimiterOptions {
|
|
@@ -393,6 +398,15 @@ export class RLWrapperBlackAndWhite extends RateLimiterAbstract {
|
|
|
393
398
|
constructor(opts: IRLWrapperBlackAndWhiteOptions);
|
|
394
399
|
}
|
|
395
400
|
|
|
401
|
+
interface IRLWrapperTimeoutsOptions extends IRateLimiterOptions {
|
|
402
|
+
limiter: RateLimiterAbstract;
|
|
403
|
+
timeoutMs?: number;
|
|
404
|
+
}
|
|
405
|
+
|
|
406
|
+
export class RLWrapperTimeouts extends RateLimiterInsuredAbstract {
|
|
407
|
+
constructor(opts: IRLWrapperTimeoutsOptions);
|
|
408
|
+
}
|
|
409
|
+
|
|
396
410
|
interface IRateLimiterQueueOpts {
|
|
397
411
|
maxQueueSize?: number;
|
|
398
412
|
}
|