@depup/rate-limiter-flexible 9.1.1-depup.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 (42) hide show
  1. package/LICENSE.md +7 -0
  2. package/README.md +25 -0
  3. package/changes.json +5 -0
  4. package/index.js +55 -0
  5. package/lib/BurstyRateLimiter.js +78 -0
  6. package/lib/ExpressBruteFlexible.js +359 -0
  7. package/lib/RLWrapperBlackAndWhite.js +195 -0
  8. package/lib/RLWrapperTimeouts.js +82 -0
  9. package/lib/RateLimiterAbstract.js +125 -0
  10. package/lib/RateLimiterCluster.js +367 -0
  11. package/lib/RateLimiterDrizzle.js +174 -0
  12. package/lib/RateLimiterDrizzleNonAtomic.js +175 -0
  13. package/lib/RateLimiterDynamo.js +401 -0
  14. package/lib/RateLimiterEtcd.js +63 -0
  15. package/lib/RateLimiterEtcdNonAtomic.js +80 -0
  16. package/lib/RateLimiterInsuredAbstract.js +112 -0
  17. package/lib/RateLimiterMemcache.js +150 -0
  18. package/lib/RateLimiterMemory.js +106 -0
  19. package/lib/RateLimiterMongo.js +261 -0
  20. package/lib/RateLimiterMySQL.js +400 -0
  21. package/lib/RateLimiterPostgres.js +351 -0
  22. package/lib/RateLimiterPrisma.js +127 -0
  23. package/lib/RateLimiterQueue.js +131 -0
  24. package/lib/RateLimiterRedis.js +209 -0
  25. package/lib/RateLimiterRedisNonAtomic.js +195 -0
  26. package/lib/RateLimiterRes.js +64 -0
  27. package/lib/RateLimiterSQLite.js +338 -0
  28. package/lib/RateLimiterStoreAbstract.js +349 -0
  29. package/lib/RateLimiterUnion.js +51 -0
  30. package/lib/RateLimiterValkey.js +117 -0
  31. package/lib/RateLimiterValkeyGlide.js +273 -0
  32. package/lib/component/BlockedKeys/BlockedKeys.js +75 -0
  33. package/lib/component/BlockedKeys/index.js +3 -0
  34. package/lib/component/MemoryStorage/MemoryStorage.js +83 -0
  35. package/lib/component/MemoryStorage/Record.js +40 -0
  36. package/lib/component/MemoryStorage/index.js +3 -0
  37. package/lib/component/RateLimiterEtcdTransactionFailedError.js +10 -0
  38. package/lib/component/RateLimiterQueueError.js +13 -0
  39. package/lib/component/RateLimiterSetupError.js +10 -0
  40. package/lib/constants.js +21 -0
  41. package/package.json +100 -0
  42. package/types.d.ts +581 -0
package/LICENSE.md ADDED
@@ -0,0 +1,7 @@
1
+ ## ISC License (ISC)
2
+
3
+ Copyright 2019 Roman Voloboev
4
+
5
+ Permission to use, copy, modify, and/or distribute this software for any purpose with or without fee is hereby granted, provided that the above copyright notice and this permission notice appear in all copies.
6
+
7
+ THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
package/README.md ADDED
@@ -0,0 +1,25 @@
1
+ # @depup/rate-limiter-flexible
2
+
3
+ > Dependency-bumped version of [rate-limiter-flexible](https://www.npmjs.com/package/rate-limiter-flexible)
4
+
5
+ Generated by [DepUp](https://github.com/depup/npm) -- all production
6
+ dependencies bumped to latest versions.
7
+
8
+ ## Installation
9
+
10
+ ```bash
11
+ npm install @depup/rate-limiter-flexible
12
+ ```
13
+
14
+ | Field | Value |
15
+ |-------|-------|
16
+ | Original | [rate-limiter-flexible](https://www.npmjs.com/package/rate-limiter-flexible) @ 9.1.1 |
17
+ | Processed | 2026-03-09 |
18
+ | Smoke test | passed |
19
+ | Deps updated | 0 |
20
+
21
+ ---
22
+
23
+ Source: https://github.com/depup/npm | Original: https://www.npmjs.com/package/rate-limiter-flexible
24
+
25
+ License inherited from the original package.
package/changes.json ADDED
@@ -0,0 +1,5 @@
1
+ {
2
+ "bumped": {},
3
+ "timestamp": "2026-03-09T05:24:38.672Z",
4
+ "totalUpdated": 0
5
+ }
package/index.js ADDED
@@ -0,0 +1,55 @@
1
+ const RateLimiterRedis = require('./lib/RateLimiterRedis');
2
+ const RateLimiterRedisNonAtomic = require('./lib/RateLimiterRedisNonAtomic');
3
+ const RateLimiterMongo = require('./lib/RateLimiterMongo');
4
+ const RateLimiterMySQL = require('./lib/RateLimiterMySQL');
5
+ const RateLimiterPostgres = require('./lib/RateLimiterPostgres');
6
+ const { RateLimiterClusterMaster, RateLimiterClusterMasterPM2, RateLimiterCluster } = require('./lib/RateLimiterCluster');
7
+ const RateLimiterMemory = require('./lib/RateLimiterMemory');
8
+ const RateLimiterMemcache = require('./lib/RateLimiterMemcache');
9
+ const RLWrapperBlackAndWhite = require('./lib/RLWrapperBlackAndWhite');
10
+ const RLWrapperTimeouts = require('./lib/RLWrapperTimeouts');
11
+ const RateLimiterUnion = require('./lib/RateLimiterUnion');
12
+ const RateLimiterQueue = require('./lib/RateLimiterQueue');
13
+ const BurstyRateLimiter = require('./lib/BurstyRateLimiter');
14
+ const RateLimiterRes = require('./lib/RateLimiterRes');
15
+ const RateLimiterDynamo = require('./lib/RateLimiterDynamo');
16
+ const RateLimiterPrisma = require('./lib/RateLimiterPrisma');
17
+ const RateLimiterDrizzle = require('./lib/RateLimiterDrizzle');
18
+ const RateLimiterDrizzleNonAtomic = require('./lib/RateLimiterDrizzleNonAtomic');
19
+ const RateLimiterValkey = require('./lib/RateLimiterValkey');
20
+ const RateLimiterValkeyGlide = require('./lib/RateLimiterValkeyGlide');
21
+ const RateLimiterSQLite = require('./lib/RateLimiterSQLite');
22
+ const RateLimiterEtcd = require('./lib/RateLimiterEtcd');
23
+ const RateLimiterEtcdNonAtomic = require('./lib/RateLimiterEtcdNonAtomic');
24
+ const RateLimiterQueueError = require('./lib/component/RateLimiterQueueError');
25
+ const RateLimiterEtcdTransactionFailedError = require('./lib/component/RateLimiterEtcdTransactionFailedError');
26
+
27
+ module.exports = {
28
+ RateLimiterRedis,
29
+ RateLimiterRedisNonAtomic,
30
+ RateLimiterMongo,
31
+ RateLimiterMySQL,
32
+ RateLimiterPostgres,
33
+ RateLimiterMemory,
34
+ RateLimiterMemcache,
35
+ RateLimiterClusterMaster,
36
+ RateLimiterClusterMasterPM2,
37
+ RateLimiterCluster,
38
+ RLWrapperBlackAndWhite,
39
+ RLWrapperTimeouts,
40
+ RateLimiterUnion,
41
+ RateLimiterQueue,
42
+ BurstyRateLimiter,
43
+ RateLimiterRes,
44
+ RateLimiterDynamo,
45
+ RateLimiterPrisma,
46
+ RateLimiterValkey,
47
+ RateLimiterValkeyGlide,
48
+ RateLimiterSQLite,
49
+ RateLimiterEtcd,
50
+ RateLimiterDrizzle,
51
+ RateLimiterDrizzleNonAtomic,
52
+ RateLimiterEtcdNonAtomic,
53
+ RateLimiterQueueError,
54
+ RateLimiterEtcdTransactionFailedError,
55
+ };
@@ -0,0 +1,78 @@
1
+ const RateLimiterRes = require("./RateLimiterRes");
2
+
3
+ /**
4
+ * Bursty rate limiter exposes only msBeforeNext time and doesn't expose points from bursty limiter by default
5
+ * @type {BurstyRateLimiter}
6
+ */
7
+ module.exports = class BurstyRateLimiter {
8
+ constructor(rateLimiter, burstLimiter) {
9
+ this._rateLimiter = rateLimiter;
10
+ this._burstLimiter = burstLimiter
11
+ }
12
+
13
+ /**
14
+ * Merge rate limiter response objects. Responses can be null
15
+ *
16
+ * @param {RateLimiterRes} [rlRes] Rate limiter response
17
+ * @param {RateLimiterRes} [blRes] Bursty limiter response
18
+ */
19
+ _combineRes(rlRes, blRes) {
20
+ if (!rlRes) {
21
+ return null
22
+ }
23
+
24
+ return new RateLimiterRes(
25
+ rlRes.remainingPoints,
26
+ Math.min(rlRes.msBeforeNext, blRes ? blRes.msBeforeNext : 0),
27
+ rlRes.consumedPoints,
28
+ rlRes.isFirstInDuration
29
+ )
30
+ }
31
+
32
+ /**
33
+ * @param key
34
+ * @param pointsToConsume
35
+ * @param options
36
+ * @returns {Promise<any>}
37
+ */
38
+ consume(key, pointsToConsume = 1, options = {}) {
39
+ return this._rateLimiter.consume(key, pointsToConsume, options)
40
+ .catch((rlRej) => {
41
+ if (rlRej instanceof RateLimiterRes) {
42
+ return this._burstLimiter.consume(key, pointsToConsume, options)
43
+ .then((blRes) => {
44
+ return Promise.resolve(this._combineRes(rlRej, blRes))
45
+ })
46
+ .catch((blRej) => {
47
+ if (blRej instanceof RateLimiterRes) {
48
+ return Promise.reject(this._combineRes(rlRej, blRej))
49
+ } else {
50
+ return Promise.reject(blRej)
51
+ }
52
+ }
53
+ )
54
+ } else {
55
+ return Promise.reject(rlRej)
56
+ }
57
+ })
58
+ }
59
+
60
+ /**
61
+ * It doesn't expose available points from burstLimiter
62
+ *
63
+ * @param key
64
+ * @returns {Promise<RateLimiterRes>}
65
+ */
66
+ get(key) {
67
+ return Promise.all([
68
+ this._rateLimiter.get(key),
69
+ this._burstLimiter.get(key),
70
+ ]).then(([rlRes, blRes]) => {
71
+ return this._combineRes(rlRes, blRes);
72
+ });
73
+ }
74
+
75
+ get points() {
76
+ return this._rateLimiter.points;
77
+ }
78
+ };
@@ -0,0 +1,359 @@
1
+ const {
2
+ LIMITER_TYPES,
3
+ ERR_UNKNOWN_LIMITER_TYPE_MESSAGE,
4
+ } = require('./constants');
5
+ const crypto = require('crypto');
6
+ const {
7
+ RateLimiterMemory,
8
+ RateLimiterCluster,
9
+ RateLimiterMemcache,
10
+ RateLimiterMongo,
11
+ RateLimiterMySQL,
12
+ RateLimiterPostgres,
13
+ RateLimiterRedis,
14
+ RateLimiterValkey,
15
+ RateLimiterValkeyGlide,
16
+ } = require('../index');
17
+
18
+ function getDelayMs(count, delays, maxWait) {
19
+ let msDelay = maxWait;
20
+ const delayIndex = count - 1;
21
+ if (delayIndex >= 0 && delayIndex < delays.length) {
22
+ msDelay = delays[delayIndex];
23
+ }
24
+
25
+ return msDelay;
26
+ }
27
+
28
+ const ExpressBruteFlexible = function (limiterType, options) {
29
+ ExpressBruteFlexible.instanceCount++;
30
+ this.name = `brute${ExpressBruteFlexible.instanceCount}`;
31
+
32
+ this.options = Object.assign({}, ExpressBruteFlexible.defaults, options);
33
+ if (this.options.minWait < 1) {
34
+ this.options.minWait = 1;
35
+ }
36
+
37
+ const validLimiterTypes = Object.keys(ExpressBruteFlexible.LIMITER_TYPES).map(k => ExpressBruteFlexible.LIMITER_TYPES[k]);
38
+ if (!validLimiterTypes.includes(limiterType)) {
39
+ throw new Error(ERR_UNKNOWN_LIMITER_TYPE_MESSAGE);
40
+ }
41
+ this.limiterType = limiterType;
42
+
43
+ this.delays = [this.options.minWait];
44
+ while (this.delays[this.delays.length - 1] < this.options.maxWait) {
45
+ const nextNum = this.delays[this.delays.length - 1] + (this.delays.length > 1 ? this.delays[this.delays.length - 2] : 0);
46
+ this.delays.push(nextNum);
47
+ }
48
+ this.delays[this.delays.length - 1] = this.options.maxWait;
49
+
50
+ // set default lifetime
51
+ if (typeof this.options.lifetime === 'undefined') {
52
+ this.options.lifetime = Math.ceil((this.options.maxWait / 1000) * (this.delays.length + this.options.freeRetries));
53
+ }
54
+
55
+ this.prevent = this.getMiddleware({
56
+ prefix: this.options.prefix,
57
+ });
58
+ };
59
+
60
+ ExpressBruteFlexible.prototype.getMiddleware = function (options) {
61
+ const opts = Object.assign({}, options);
62
+ const commonKeyPrefix = opts.prefix || '';
63
+ const freeLimiterOptions = {
64
+ storeClient: this.options.storeClient,
65
+ storeType: this.options.storeType,
66
+ keyPrefix: `${commonKeyPrefix}free`,
67
+ dbName: this.options.dbName,
68
+ tableName: this.options.tableName,
69
+ points: this.options.freeRetries > 0 ? this.options.freeRetries - 1 : 0,
70
+ duration: this.options.lifetime,
71
+ };
72
+
73
+ const blockLimiterOptions = {
74
+ storeClient: this.options.storeClient,
75
+ storeType: this.options.storeType,
76
+ keyPrefix: `${commonKeyPrefix}block`,
77
+ dbName: this.options.dbName,
78
+ tableName: this.options.tableName,
79
+ points: 1,
80
+ duration: Math.min(this.options.lifetime, Math.ceil((this.options.maxWait / 1000))),
81
+ };
82
+
83
+ const counterLimiterOptions = {
84
+ storeClient: this.options.storeClient,
85
+ storeType: this.options.storeType,
86
+ keyPrefix: `${commonKeyPrefix}counter`,
87
+ dbName: this.options.dbName,
88
+ tableName: this.options.tableName,
89
+ points: 1,
90
+ duration: this.options.lifetime,
91
+ };
92
+
93
+ switch (this.limiterType) {
94
+ case 'memory':
95
+ this.freeLimiter = new RateLimiterMemory(freeLimiterOptions);
96
+ this.blockLimiter = new RateLimiterMemory(blockLimiterOptions);
97
+ this.counterLimiter = new RateLimiterMemory(counterLimiterOptions);
98
+ break;
99
+ case 'cluster':
100
+ this.freeLimiter = new RateLimiterCluster(freeLimiterOptions);
101
+ this.blockLimiter = new RateLimiterCluster(blockLimiterOptions);
102
+ this.counterLimiter = new RateLimiterCluster(counterLimiterOptions);
103
+ break;
104
+ case 'memcache':
105
+ this.freeLimiter = new RateLimiterMemcache(freeLimiterOptions);
106
+ this.blockLimiter = new RateLimiterMemcache(blockLimiterOptions);
107
+ this.counterLimiter = new RateLimiterMemcache(counterLimiterOptions);
108
+ break;
109
+ case 'mongo':
110
+ this.freeLimiter = new RateLimiterMongo(freeLimiterOptions);
111
+ this.blockLimiter = new RateLimiterMongo(blockLimiterOptions);
112
+ this.counterLimiter = new RateLimiterMongo(counterLimiterOptions);
113
+ break;
114
+ case 'mysql':
115
+ this.freeLimiter = new RateLimiterMySQL(freeLimiterOptions);
116
+ this.blockLimiter = new RateLimiterMySQL(blockLimiterOptions);
117
+ this.counterLimiter = new RateLimiterMySQL(counterLimiterOptions);
118
+ break;
119
+ case 'postgres':
120
+ this.freeLimiter = new RateLimiterPostgres(freeLimiterOptions);
121
+ this.blockLimiter = new RateLimiterPostgres(blockLimiterOptions);
122
+ this.counterLimiter = new RateLimiterPostgres(counterLimiterOptions);
123
+ break;
124
+ case 'valkey-glide':
125
+ this.freeLimiter = new RateLimiterValkeyGlide(freeLimiterOptions);
126
+ this.blockLimiter = new RateLimiterValkeyGlide(blockLimiterOptions);
127
+ this.counterLimiter = new RateLimiterValkeyGlide(counterLimiterOptions);
128
+ break;
129
+ case 'valkey':
130
+ this.freeLimiter = new RateLimiterValkey(freeLimiterOptions);
131
+ this.blockLimiter = new RateLimiterValkey(blockLimiterOptions);
132
+ this.counterLimiter = new RateLimiterValkey(counterLimiterOptions);
133
+ break;
134
+ case 'redis':
135
+ this.freeLimiter = new RateLimiterRedis(freeLimiterOptions);
136
+ this.blockLimiter = new RateLimiterRedis(blockLimiterOptions);
137
+ this.counterLimiter = new RateLimiterRedis(counterLimiterOptions);
138
+ break;
139
+ default:
140
+ throw new Error(ERR_UNKNOWN_LIMITER_TYPE_MESSAGE);
141
+ }
142
+
143
+ let keyFunc = opts.key;
144
+ if (typeof keyFunc !== 'function') {
145
+ keyFunc = function (req, res, next) {
146
+ next(opts.key);
147
+ };
148
+ }
149
+
150
+ const getFailCallback = (() => (typeof opts.failCallback === 'undefined' ? this.options.failCallback : opts.failCallback));
151
+
152
+ return (req, res, next) => {
153
+ const cannotIncrementErrorObjectBase = {
154
+ req,
155
+ res,
156
+ next,
157
+ message: 'Cannot increment request count',
158
+ };
159
+
160
+ keyFunc(req, res, (key) => {
161
+ if (!opts.ignoreIP) {
162
+ key = ExpressBruteFlexible._getKey([req.ip, this.name, key]);
163
+ } else {
164
+ key = ExpressBruteFlexible._getKey([this.name, key]);
165
+ }
166
+
167
+ // attach a simpler "reset" function to req.brute.reset
168
+ if (this.options.attachResetToRequest) {
169
+ let reset = ((callback) => {
170
+ Promise.all([
171
+ this.freeLimiter.delete(key),
172
+ this.blockLimiter.delete(key),
173
+ this.counterLimiter.delete(key),
174
+ ]).then(() => {
175
+ if (typeof callback === 'function') {
176
+ process.nextTick(() => {
177
+ callback();
178
+ });
179
+ }
180
+ }).catch((err) => {
181
+ if (typeof callback === 'function') {
182
+ process.nextTick(() => {
183
+ callback(err);
184
+ });
185
+ }
186
+ });
187
+ });
188
+
189
+ if (req.brute && req.brute.reset) {
190
+ // wrap existing reset if one exists
191
+ const oldReset = req.brute.reset;
192
+ const newReset = reset;
193
+ reset = function (callback) {
194
+ oldReset(() => {
195
+ newReset(callback);
196
+ });
197
+ };
198
+ }
199
+ req.brute = {
200
+ reset,
201
+ };
202
+ }
203
+
204
+ this.freeLimiter.consume(key)
205
+ .then(() => {
206
+ if (typeof next === 'function') {
207
+ next();
208
+ }
209
+ })
210
+ .catch(() => {
211
+ Promise.all([
212
+ this.blockLimiter.get(key),
213
+ this.counterLimiter.get(key),
214
+ ])
215
+ .then((allRes) => {
216
+ const [blockRes, counterRes] = allRes;
217
+
218
+ if (blockRes === null) {
219
+ const msDelay = getDelayMs(
220
+ counterRes ? counterRes.consumedPoints + 1 : 1,
221
+ this.delays,
222
+ // eslint-disable-next-line
223
+ this.options.maxWait
224
+ );
225
+
226
+ this.blockLimiter.penalty(key, 1, { customDuration: Math.ceil(msDelay / 1000) })
227
+ .then((blockPenaltyRes) => {
228
+ if (blockPenaltyRes.consumedPoints === 1) {
229
+ this.counterLimiter.penalty(key)
230
+ .then(() => {
231
+ if (typeof next === 'function') {
232
+ next();
233
+ }
234
+ })
235
+ .catch((err) => {
236
+ this.options.handleStoreError(Object.assign({}, cannotIncrementErrorObjectBase, { parent: err }));
237
+ });
238
+ } else {
239
+ const nextValidDate = new Date(Date.now() + blockPenaltyRes.msBeforeNext);
240
+
241
+ const failCallback = getFailCallback();
242
+ if (typeof failCallback === 'function') {
243
+ failCallback(req, res, next, nextValidDate);
244
+ }
245
+ }
246
+ })
247
+ .catch((err) => {
248
+ this.options.handleStoreError(Object.assign({}, cannotIncrementErrorObjectBase, { parent: err }));
249
+ });
250
+ } else {
251
+ const nextValidDate = new Date(Date.now() + blockRes.msBeforeNext);
252
+
253
+ const failCallback = getFailCallback();
254
+ if (typeof failCallback === 'function') {
255
+ failCallback(req, res, next, nextValidDate);
256
+ }
257
+ }
258
+ })
259
+ .catch((err) => {
260
+ this.options.handleStoreError(Object.assign({}, cannotIncrementErrorObjectBase, { parent: err }));
261
+ });
262
+ });
263
+ });
264
+ };
265
+ };
266
+
267
+ ExpressBruteFlexible.prototype.reset = function (ip, key, callback) {
268
+ let keyArgs = [];
269
+ if (ip) {
270
+ keyArgs.push(ip)
271
+ }
272
+ keyArgs.push(this.name);
273
+ keyArgs.push(key);
274
+ const ebKey = ExpressBruteFlexible._getKey(keyArgs);
275
+
276
+ Promise.all([
277
+ this.freeLimiter.delete(ebKey),
278
+ this.blockLimiter.delete(ebKey),
279
+ this.counterLimiter.delete(ebKey),
280
+ ]).then(() => {
281
+ if (typeof callback === 'function') {
282
+ process.nextTick(() => {
283
+ callback();
284
+ });
285
+ }
286
+ }).catch((err) => {
287
+ this.options.handleStoreError({
288
+ message: 'Cannot reset request count',
289
+ parent: err,
290
+ key,
291
+ ip,
292
+ });
293
+ });
294
+ };
295
+
296
+ ExpressBruteFlexible._getKey = function (arr) {
297
+ let key = '';
298
+
299
+ arr.forEach((part) => {
300
+ if (part) {
301
+ key += crypto.createHash('sha256').update(part).digest('base64');
302
+ }
303
+ });
304
+
305
+ return crypto.createHash('sha256').update(key).digest('base64');
306
+ };
307
+
308
+ const setRetryAfter = function (res, nextValidRequestDate) {
309
+ const secondUntilNextRequest = Math.ceil((nextValidRequestDate.getTime() - Date.now()) / 1000);
310
+ res.header('Retry-After', secondUntilNextRequest);
311
+ };
312
+ ExpressBruteFlexible.FailTooManyRequests = function (req, res, next, nextValidRequestDate) {
313
+ setRetryAfter(res, nextValidRequestDate);
314
+ res.status(429);
315
+ res.send({
316
+ error: {
317
+ text: 'Too many requests in this time frame.',
318
+ nextValidRequestDate,
319
+ },
320
+ });
321
+ };
322
+ ExpressBruteFlexible.FailForbidden = function (req, res, next, nextValidRequestDate) {
323
+ setRetryAfter(res, nextValidRequestDate);
324
+ res.status(403);
325
+ res.send({
326
+ error: {
327
+ text: 'Too many requests in this time frame.',
328
+ nextValidRequestDate,
329
+ },
330
+ });
331
+ };
332
+ ExpressBruteFlexible.FailMark = function (req, res, next, nextValidRequestDate) {
333
+ res.status(429);
334
+ setRetryAfter(res, nextValidRequestDate);
335
+ res.nextValidRequestDate = nextValidRequestDate;
336
+ next();
337
+ };
338
+
339
+ ExpressBruteFlexible.defaults = {
340
+ freeRetries: 2,
341
+ attachResetToRequest: true,
342
+ minWait: 500,
343
+ maxWait: 1000 * 60 * 15,
344
+ failCallback: ExpressBruteFlexible.FailTooManyRequests,
345
+ handleStoreError(err) {
346
+ // eslint-disable-next-line
347
+ throw {
348
+ message: err.message,
349
+ parent: err.parent,
350
+ };
351
+ },
352
+ };
353
+
354
+ ExpressBruteFlexible.LIMITER_TYPES = LIMITER_TYPES;
355
+
356
+ ExpressBruteFlexible.instanceCount = 0;
357
+
358
+
359
+ module.exports = ExpressBruteFlexible;