rate-limiter-flexible 5.0.5 → 6.1.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 +7 -5
- package/index.js +4 -0
- package/lib/RateLimiterSQLite.js +207 -0
- package/lib/RateLimiterValkey.js +117 -0
- package/lib/constants.js +1 -0
- package/lib/index.d.ts +12 -0
- package/package.json +4 -2
package/README.md
CHANGED
|
@@ -3,7 +3,7 @@
|
|
|
3
3
|
[![node version][node-image]][node-url]
|
|
4
4
|
[](https://github.com/denoland/deno)
|
|
5
5
|
|
|
6
|
-
[node-image]: https://img.shields.io/badge/node.js-%3E=
|
|
6
|
+
[node-image]: https://img.shields.io/badge/node.js-%3E=_18.0-green.svg?style=flat-square
|
|
7
7
|
[node-url]: http://nodejs.org/download/
|
|
8
8
|
|
|
9
9
|
<img src="img/rlflx-logo-small.png" width="50" alt="Logo"/>
|
|
@@ -12,7 +12,7 @@
|
|
|
12
12
|
|
|
13
13
|
**rate-limiter-flexible** counts and limits the number of actions by key and protects from DDoS and brute force attacks at any scale.
|
|
14
14
|
|
|
15
|
-
It works with _Redis_, _Prisma_, _DynamoDB_, process _Memory_, _Cluster_ or _PM2_, _Memcached_, _MongoDB_, _MySQL_, and _PostgreSQL_.
|
|
15
|
+
It works with _Redis_, _Valkey_, _Prisma_, _DynamoDB_, process _Memory_, _Cluster_ or _PM2_, _Memcached_, _MongoDB_, _MySQL_, _SQLite_, and _PostgreSQL_.
|
|
16
16
|
|
|
17
17
|
Memory limiter also works in the browser.
|
|
18
18
|
|
|
@@ -24,7 +24,7 @@ Memory limiter also works in the browser.
|
|
|
24
24
|
|
|
25
25
|
**Ready for growth.** It provides a unified API for all limiters. Whenever your application grows, it is ready. Prepare your limiters in minutes.
|
|
26
26
|
|
|
27
|
-
**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.
|
|
27
|
+
**Friendly.** No matter which node package you prefer: `redis` or `ioredis`, `iovalkey`, `sequelize`/`typeorm` or `knex`, `memcached`, native driver or `mongoose`. It works with all of them.
|
|
28
28
|
|
|
29
29
|
**In-memory blocks.** Avoid extra requests to store with [inMemoryBlockOnConsumed](https://github.com/animir/node-rate-limiter-flexible/wiki/Options#inmemoryblockonconsumed).
|
|
30
30
|
|
|
@@ -141,10 +141,12 @@ Some copy/paste examples on Wiki:
|
|
|
141
141
|
* [Memory](https://github.com/animir/node-rate-limiter-flexible/wiki/Memory)
|
|
142
142
|
* [DynamoDb](https://github.com/animir/node-rate-limiter-flexible/wiki/DynamoDB)
|
|
143
143
|
* [Prisma](https://github.com/animir/node-rate-limiter-flexible/wiki/Prisma)
|
|
144
|
+
* [Valkey](https://github.com/animir/node-rate-limiter-flexible/wiki/Valkey)
|
|
144
145
|
* [BurstyRateLimiter](https://github.com/animir/node-rate-limiter-flexible/wiki/BurstyRateLimiter) Traffic burst support
|
|
145
146
|
* [Mongo](https://github.com/animir/node-rate-limiter-flexible/wiki/Mongo) (with [sharding support](https://github.com/animir/node-rate-limiter-flexible/wiki/Mongo#mongodb-sharding-options))
|
|
146
147
|
* [MySQL](https://github.com/animir/node-rate-limiter-flexible/wiki/MySQL) (support Sequelize and Knex)
|
|
147
148
|
* [Postgres](https://github.com/animir/node-rate-limiter-flexible/wiki/PostgreSQL) (support Sequelize, TypeORM and Knex)
|
|
149
|
+
* [SQLite](https://github.com/animir/node-rate-limiter-flexible/wiki/SQLite)
|
|
148
150
|
* [RateLimiterCluster](https://github.com/animir/node-rate-limiter-flexible/wiki/Cluster) ([PM2 cluster docs read here](https://github.com/animir/node-rate-limiter-flexible/wiki/PM2-cluster))
|
|
149
151
|
* [Memcache](https://github.com/animir/node-rate-limiter-flexible/wiki/Memcache)
|
|
150
152
|
* [RateLimiterUnion](https://github.com/animir/node-rate-limiter-flexible/wiki/RateLimiterUnion) Combine 2 or more limiters to act as single
|
|
@@ -186,8 +188,8 @@ See [releases](https://github.com/animir/node-rate-limiter-flexible/releases) fo
|
|
|
186
188
|
* [storeType](https://github.com/animir/node-rate-limiter-flexible/wiki/Options#storetype) Have to be set to `knex`, if you use it.
|
|
187
189
|
* [dbName](https://github.com/animir/node-rate-limiter-flexible/wiki/Options#dbname) Where to store points.
|
|
188
190
|
* [tableName](https://github.com/animir/node-rate-limiter-flexible/wiki/Options#tablename) Table/collection.
|
|
189
|
-
* [tableCreated](https://github.com/animir/node-rate-limiter-flexible/wiki/Options#tablecreated) Is table already created in MySQL or PostgreSQL.
|
|
190
|
-
* [clearExpiredByTimeout](https://github.com/animir/node-rate-limiter-flexible/wiki/Options#clearexpiredbytimeout) For MySQL and PostgreSQL.
|
|
191
|
+
* [tableCreated](https://github.com/animir/node-rate-limiter-flexible/wiki/Options#tablecreated) Is table already created in MySQL, SQLite or PostgreSQL.
|
|
192
|
+
* [clearExpiredByTimeout](https://github.com/animir/node-rate-limiter-flexible/wiki/Options#clearexpiredbytimeout) For MySQL, SQLite and PostgreSQL.
|
|
191
193
|
|
|
192
194
|
Smooth out traffic peaks:
|
|
193
195
|
* [execEvenly](https://github.com/animir/node-rate-limiter-flexible/wiki/Options#execevenly)
|
package/index.js
CHANGED
|
@@ -12,6 +12,8 @@ const BurstyRateLimiter = require('./lib/BurstyRateLimiter');
|
|
|
12
12
|
const RateLimiterRes = require('./lib/RateLimiterRes');
|
|
13
13
|
const RateLimiterDynamo = require('./lib/RateLimiterDynamo');
|
|
14
14
|
const RateLimiterPrisma = require('./lib/RateLimiterPrisma');
|
|
15
|
+
const RateLimiterValkey = require('./lib/RateLimiterValkey');
|
|
16
|
+
const RateLimiterSQLite = require('./lib/RateLimiterSQLite');
|
|
15
17
|
|
|
16
18
|
module.exports = {
|
|
17
19
|
RateLimiterRedis,
|
|
@@ -30,4 +32,6 @@ module.exports = {
|
|
|
30
32
|
RateLimiterRes,
|
|
31
33
|
RateLimiterDynamo,
|
|
32
34
|
RateLimiterPrisma,
|
|
35
|
+
RateLimiterValkey,
|
|
36
|
+
RateLimiterSQLite,
|
|
33
37
|
};
|
|
@@ -0,0 +1,207 @@
|
|
|
1
|
+
const RateLimiterStoreAbstract = require("./RateLimiterStoreAbstract");
|
|
2
|
+
const RateLimiterRes = require("./RateLimiterRes");
|
|
3
|
+
|
|
4
|
+
class RateLimiterSQLite extends RateLimiterStoreAbstract {
|
|
5
|
+
/**
|
|
6
|
+
* @callback callback
|
|
7
|
+
* @param {Object} err
|
|
8
|
+
*
|
|
9
|
+
* @param {Object} opts
|
|
10
|
+
* @param {callback} cb
|
|
11
|
+
* Defaults {
|
|
12
|
+
* ... see other in RateLimiterStoreAbstract
|
|
13
|
+
*
|
|
14
|
+
* storeClient: sqliteClient, // SQLite database instance
|
|
15
|
+
* tableName: 'string',
|
|
16
|
+
* }
|
|
17
|
+
*/
|
|
18
|
+
constructor(opts, cb = null) {
|
|
19
|
+
super(opts);
|
|
20
|
+
|
|
21
|
+
this.client = opts.storeClient;
|
|
22
|
+
this.tableName = opts.tableName;
|
|
23
|
+
this.tableCreated = opts.tableCreated || false;
|
|
24
|
+
this.clearExpiredByTimeout = opts.clearExpiredByTimeout;
|
|
25
|
+
|
|
26
|
+
if (!/^[A-Za-z0-9_]*$/.test(this.tableName)) {
|
|
27
|
+
const err = new Error("Table name must contain only letters and numbers");
|
|
28
|
+
if (typeof cb === "function") {
|
|
29
|
+
return cb(err);
|
|
30
|
+
}
|
|
31
|
+
throw err;
|
|
32
|
+
}
|
|
33
|
+
|
|
34
|
+
if (!this.tableCreated) {
|
|
35
|
+
this._createDbAndTable()
|
|
36
|
+
.then(() => {
|
|
37
|
+
this.tableCreated = true;
|
|
38
|
+
|
|
39
|
+
if (this.clearExpiredByTimeout) {
|
|
40
|
+
this._clearExpiredHourAgo();
|
|
41
|
+
}
|
|
42
|
+
if (typeof cb === "function") {
|
|
43
|
+
cb();
|
|
44
|
+
}
|
|
45
|
+
})
|
|
46
|
+
.catch((err) => {
|
|
47
|
+
if (typeof cb === "function") {
|
|
48
|
+
cb(err);
|
|
49
|
+
} else {
|
|
50
|
+
throw err;
|
|
51
|
+
}
|
|
52
|
+
});
|
|
53
|
+
} else {
|
|
54
|
+
if (this.clearExpiredByTimeout) {
|
|
55
|
+
this._clearExpiredHourAgo();
|
|
56
|
+
}
|
|
57
|
+
if (typeof cb === "function") {
|
|
58
|
+
cb();
|
|
59
|
+
}
|
|
60
|
+
}
|
|
61
|
+
}
|
|
62
|
+
async _createDbAndTable() {
|
|
63
|
+
return new Promise((resolve, reject) => {
|
|
64
|
+
const createTableSQL = this._getCreateTableSQL();
|
|
65
|
+
this.client.run(createTableSQL, (err) => {
|
|
66
|
+
if (err) {
|
|
67
|
+
reject(err);
|
|
68
|
+
} else {
|
|
69
|
+
resolve();
|
|
70
|
+
}
|
|
71
|
+
});
|
|
72
|
+
});
|
|
73
|
+
}
|
|
74
|
+
|
|
75
|
+
_getCreateTableSQL() {
|
|
76
|
+
return `CREATE TABLE IF NOT EXISTS ${this.tableName} (
|
|
77
|
+
key TEXT PRIMARY KEY,
|
|
78
|
+
points INTEGER NOT NULL DEFAULT 0,
|
|
79
|
+
expire INTEGER
|
|
80
|
+
)`;
|
|
81
|
+
}
|
|
82
|
+
|
|
83
|
+
_clearExpiredHourAgo() {
|
|
84
|
+
if (this._clearExpiredTimeoutId) {
|
|
85
|
+
clearTimeout(this._clearExpiredTimeoutId);
|
|
86
|
+
}
|
|
87
|
+
this._clearExpiredTimeoutId = setTimeout(() => {
|
|
88
|
+
this.clearExpired(Date.now() - 3600000) // Never rejected
|
|
89
|
+
.then(() => {
|
|
90
|
+
this._clearExpiredHourAgo();
|
|
91
|
+
});
|
|
92
|
+
}, 300000);
|
|
93
|
+
this._clearExpiredTimeoutId.unref();
|
|
94
|
+
}
|
|
95
|
+
|
|
96
|
+
clearExpired(nowMs) {
|
|
97
|
+
return new Promise((resolve) => {
|
|
98
|
+
this.client.run(
|
|
99
|
+
`DELETE FROM ${this.tableName} WHERE expire < ?`,
|
|
100
|
+
[nowMs],
|
|
101
|
+
() => resolve()
|
|
102
|
+
);
|
|
103
|
+
});
|
|
104
|
+
}
|
|
105
|
+
|
|
106
|
+
_getRateLimiterRes(rlKey, changedPoints, result) {
|
|
107
|
+
const res = new RateLimiterRes();
|
|
108
|
+
res.isFirstInDuration = changedPoints === result.points;
|
|
109
|
+
res.consumedPoints = res.isFirstInDuration ? changedPoints : result.points;
|
|
110
|
+
res.remainingPoints = Math.max(this.points - res.consumedPoints, 0);
|
|
111
|
+
res.msBeforeNext = result.expire
|
|
112
|
+
? Math.max(result.expire - Date.now(), 0)
|
|
113
|
+
: -1;
|
|
114
|
+
|
|
115
|
+
return res;
|
|
116
|
+
}
|
|
117
|
+
|
|
118
|
+
async _upsertTransaction(rlKey, points, msDuration, forceExpire) {
|
|
119
|
+
return new Promise((resolve, reject) => {
|
|
120
|
+
const dateNow = Date.now();
|
|
121
|
+
const newExpire = msDuration > 0 ? dateNow + msDuration : null;
|
|
122
|
+
|
|
123
|
+
const upsertQuery = forceExpire
|
|
124
|
+
? `INSERT OR REPLACE INTO ${this.tableName} (key, points, expire) VALUES (?, ?, ?) RETURNING points, expire;`
|
|
125
|
+
: `
|
|
126
|
+
INSERT INTO ${this.tableName} (key, points, expire)
|
|
127
|
+
VALUES (?, ?, ?)
|
|
128
|
+
ON CONFLICT(key) DO UPDATE SET
|
|
129
|
+
points = CASE
|
|
130
|
+
WHEN expire IS NULL OR expire > ? THEN points + excluded.points
|
|
131
|
+
ELSE excluded.points
|
|
132
|
+
END,
|
|
133
|
+
expire = CASE
|
|
134
|
+
WHEN expire IS NULL OR expire > ? THEN expire
|
|
135
|
+
ELSE excluded.expire
|
|
136
|
+
END
|
|
137
|
+
RETURNING points, expire;
|
|
138
|
+
`;
|
|
139
|
+
|
|
140
|
+
const upsertParams = forceExpire
|
|
141
|
+
? [rlKey, points, newExpire]
|
|
142
|
+
: [rlKey, points, newExpire, dateNow, dateNow];
|
|
143
|
+
|
|
144
|
+
this.client.serialize(() => {
|
|
145
|
+
this.client.run("SAVEPOINT rate_limiter_trx;", (savepointErr) => {
|
|
146
|
+
if (savepointErr) return reject(savepointErr);
|
|
147
|
+
|
|
148
|
+
this.client.get(upsertQuery, upsertParams, (queryErr, row) => {
|
|
149
|
+
if (queryErr) {
|
|
150
|
+
return this.client.run(
|
|
151
|
+
"ROLLBACK TO SAVEPOINT rate_limiter_trx;",
|
|
152
|
+
() => reject(queryErr)
|
|
153
|
+
);
|
|
154
|
+
}
|
|
155
|
+
|
|
156
|
+
this.client.run("RELEASE SAVEPOINT rate_limiter_trx;", () =>
|
|
157
|
+
resolve(row)
|
|
158
|
+
);
|
|
159
|
+
});
|
|
160
|
+
});
|
|
161
|
+
});
|
|
162
|
+
});
|
|
163
|
+
}
|
|
164
|
+
_upsert(rlKey, points, msDuration, forceExpire = false) {
|
|
165
|
+
if (!this.tableCreated) {
|
|
166
|
+
return Promise.reject(Error("Table is not created yet"));
|
|
167
|
+
}
|
|
168
|
+
return this._upsertTransaction(rlKey, points, msDuration, forceExpire);
|
|
169
|
+
}
|
|
170
|
+
_get(rlKey) {
|
|
171
|
+
return new Promise((resolve, reject) => {
|
|
172
|
+
this.client.get(
|
|
173
|
+
`SELECT points, expire FROM ${this.tableName} WHERE key = ? AND (expire > ? OR expire IS NULL)`,
|
|
174
|
+
[rlKey, Date.now()],
|
|
175
|
+
(err, row) => {
|
|
176
|
+
if (err) {
|
|
177
|
+
reject(err);
|
|
178
|
+
} else {
|
|
179
|
+
resolve(row || null);
|
|
180
|
+
}
|
|
181
|
+
}
|
|
182
|
+
);
|
|
183
|
+
});
|
|
184
|
+
}
|
|
185
|
+
|
|
186
|
+
_delete(rlKey) {
|
|
187
|
+
if (!this.tableCreated) {
|
|
188
|
+
return Promise.reject(Error("Table is not created yet"));
|
|
189
|
+
}
|
|
190
|
+
|
|
191
|
+
return new Promise((resolve, reject) => {
|
|
192
|
+
this.client.run(
|
|
193
|
+
`DELETE FROM ${this.tableName} WHERE key = ?`,
|
|
194
|
+
[rlKey],
|
|
195
|
+
function (err) {
|
|
196
|
+
if (err) {
|
|
197
|
+
reject(err);
|
|
198
|
+
} else {
|
|
199
|
+
resolve(this.changes > 0);
|
|
200
|
+
}
|
|
201
|
+
}
|
|
202
|
+
);
|
|
203
|
+
});
|
|
204
|
+
}
|
|
205
|
+
}
|
|
206
|
+
|
|
207
|
+
module.exports = RateLimiterSQLite;
|
|
@@ -0,0 +1,117 @@
|
|
|
1
|
+
const RateLimiterStoreAbstract = require('./RateLimiterStoreAbstract');
|
|
2
|
+
const RateLimiterRes = require('./RateLimiterRes');
|
|
3
|
+
|
|
4
|
+
const incrTtlLuaScript = `
|
|
5
|
+
server.call('set', KEYS[1], 0, 'EX', ARGV[2], 'NX')
|
|
6
|
+
local consumed = server.call('incrby', KEYS[1], ARGV[1])
|
|
7
|
+
local ttl = server.call('pttl', KEYS[1])
|
|
8
|
+
return {consumed, ttl}
|
|
9
|
+
`;
|
|
10
|
+
|
|
11
|
+
class RateLimiterValkey extends RateLimiterStoreAbstract {
|
|
12
|
+
/**
|
|
13
|
+
*
|
|
14
|
+
* @param {Object} opts
|
|
15
|
+
* Defaults {
|
|
16
|
+
* ... see other in RateLimiterStoreAbstract
|
|
17
|
+
*
|
|
18
|
+
* storeClient: ValkeyClient
|
|
19
|
+
* rejectIfValkeyNotReady: boolean = false - reject / invoke insuranceLimiter immediately when valkey connection is not "ready"
|
|
20
|
+
* }
|
|
21
|
+
*/
|
|
22
|
+
constructor(opts) {
|
|
23
|
+
super(opts);
|
|
24
|
+
this.client = opts.storeClient;
|
|
25
|
+
|
|
26
|
+
this._rejectIfValkeyNotReady = !!opts.rejectIfValkeyNotReady;
|
|
27
|
+
this._incrTtlLuaScript = opts.customIncrTtlLuaScript || incrTtlLuaScript;
|
|
28
|
+
|
|
29
|
+
this.client.defineCommand('rlflxIncr', {
|
|
30
|
+
numberOfKeys: 1,
|
|
31
|
+
lua: this._incrTtlLuaScript,
|
|
32
|
+
});
|
|
33
|
+
}
|
|
34
|
+
|
|
35
|
+
/**
|
|
36
|
+
* Prevent actual valkey call if valkey connection is not ready
|
|
37
|
+
* @return {boolean}
|
|
38
|
+
* @private
|
|
39
|
+
*/
|
|
40
|
+
_isValkeyReady() {
|
|
41
|
+
if (!this._rejectIfValkeyNotReady) {
|
|
42
|
+
return true;
|
|
43
|
+
}
|
|
44
|
+
|
|
45
|
+
return this.client.status === 'ready';
|
|
46
|
+
}
|
|
47
|
+
|
|
48
|
+
_getRateLimiterRes(rlKey, changedPoints, result) {
|
|
49
|
+
let consumed;
|
|
50
|
+
let resTtlMs;
|
|
51
|
+
|
|
52
|
+
if (Array.isArray(result[0])) {
|
|
53
|
+
[[, consumed], [, resTtlMs]] = result;
|
|
54
|
+
} else {
|
|
55
|
+
[consumed, resTtlMs] = result;
|
|
56
|
+
}
|
|
57
|
+
|
|
58
|
+
const res = new RateLimiterRes();
|
|
59
|
+
res.consumedPoints = +consumed;
|
|
60
|
+
res.isFirstInDuration = res.consumedPoints === changedPoints;
|
|
61
|
+
res.remainingPoints = Math.max(this.points - res.consumedPoints, 0);
|
|
62
|
+
res.msBeforeNext = resTtlMs;
|
|
63
|
+
|
|
64
|
+
return res;
|
|
65
|
+
}
|
|
66
|
+
|
|
67
|
+
_upsert(rlKey, points, msDuration, forceExpire = false) {
|
|
68
|
+
if (!this._isValkeyReady()) {
|
|
69
|
+
throw new Error('Valkey connection is not ready');
|
|
70
|
+
}
|
|
71
|
+
|
|
72
|
+
const secDuration = Math.floor(msDuration / 1000);
|
|
73
|
+
|
|
74
|
+
if (forceExpire) {
|
|
75
|
+
const multi = this.client.multi();
|
|
76
|
+
|
|
77
|
+
if (secDuration > 0) {
|
|
78
|
+
multi.set(rlKey, points, 'EX', secDuration);
|
|
79
|
+
} else {
|
|
80
|
+
multi.set(rlKey, points);
|
|
81
|
+
}
|
|
82
|
+
|
|
83
|
+
return multi.pttl(rlKey).exec();
|
|
84
|
+
}
|
|
85
|
+
|
|
86
|
+
if (secDuration > 0) {
|
|
87
|
+
return this.client.rlflxIncr([rlKey, String(points), String(secDuration), String(this.points), String(this.duration)]);
|
|
88
|
+
}
|
|
89
|
+
|
|
90
|
+
return this.client.multi().incrby(rlKey, points).pttl(rlKey).exec();
|
|
91
|
+
}
|
|
92
|
+
|
|
93
|
+
_get(rlKey) {
|
|
94
|
+
if (!this._isValkeyReady()) {
|
|
95
|
+
throw new Error('Valkey connection is not ready');
|
|
96
|
+
}
|
|
97
|
+
|
|
98
|
+
return this.client
|
|
99
|
+
.multi()
|
|
100
|
+
.get(rlKey)
|
|
101
|
+
.pttl(rlKey)
|
|
102
|
+
.exec()
|
|
103
|
+
.then((result) => {
|
|
104
|
+
const [[, points]] = result;
|
|
105
|
+
if (points === null) return null;
|
|
106
|
+
return result;
|
|
107
|
+
});
|
|
108
|
+
}
|
|
109
|
+
|
|
110
|
+
_delete(rlKey) {
|
|
111
|
+
return this.client
|
|
112
|
+
.del(rlKey)
|
|
113
|
+
.then(result => result > 0);
|
|
114
|
+
}
|
|
115
|
+
}
|
|
116
|
+
|
|
117
|
+
module.exports = RateLimiterValkey;
|
package/lib/constants.js
CHANGED
package/lib/index.d.ts
CHANGED
|
@@ -258,6 +258,10 @@ interface IRateLimiterRedisOptions extends IRateLimiterStoreOptions {
|
|
|
258
258
|
customIncrTtlLuaScript?: string;
|
|
259
259
|
}
|
|
260
260
|
|
|
261
|
+
interface IRateLimiterValkeyOptions extends IRateLimiterStoreOptions {
|
|
262
|
+
customIncrTtlLuaScript?: string;
|
|
263
|
+
}
|
|
264
|
+
|
|
261
265
|
interface ICallbackReady {
|
|
262
266
|
(error?: Error): void;
|
|
263
267
|
}
|
|
@@ -291,6 +295,10 @@ export class RateLimiterRedis extends RateLimiterStoreAbstract {
|
|
|
291
295
|
constructor(opts: IRateLimiterRedisOptions);
|
|
292
296
|
}
|
|
293
297
|
|
|
298
|
+
export class RateLimiterValkey extends RateLimiterStoreAbstract {
|
|
299
|
+
constructor(opts: IRateLimiterValkeyOptions);
|
|
300
|
+
}
|
|
301
|
+
|
|
294
302
|
export interface IRateLimiterMongoFunctionOptions {
|
|
295
303
|
attrs: { [key: string]: any };
|
|
296
304
|
}
|
|
@@ -350,6 +358,10 @@ export class RateLimiterPostgres extends RateLimiterStoreAbstract {
|
|
|
350
358
|
constructor(opts: IRateLimiterPostgresOptions, cb?: ICallbackReady);
|
|
351
359
|
}
|
|
352
360
|
|
|
361
|
+
export class RateLimiterSQLite extends RateLimiterStoreAbstract {
|
|
362
|
+
constructor(opts: IRateLimiterStoreNoAutoExpiryOptions, cb?: ICallbackReady);
|
|
363
|
+
}
|
|
364
|
+
|
|
353
365
|
export class RateLimiterPrisma extends RateLimiterStoreAbstract {
|
|
354
366
|
constructor(opts: IRateLimiterStoreNoAutoExpiryOptions, cb?: ICallbackReady);
|
|
355
367
|
}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "rate-limiter-flexible",
|
|
3
|
-
"version": "
|
|
3
|
+
"version": "6.1.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": {
|
|
@@ -53,6 +53,7 @@
|
|
|
53
53
|
"eslint-plugin-node": "^6.0.1",
|
|
54
54
|
"eslint-plugin-security": "^1.4.0",
|
|
55
55
|
"ioredis": "^5.3.2",
|
|
56
|
+
"iovalkey": "^0.3.1",
|
|
56
57
|
"istanbul": "^1.1.0-alpha.1",
|
|
57
58
|
"memcached-mock": "^0.1.0",
|
|
58
59
|
"mocha": "^10.2.0",
|
|
@@ -60,7 +61,8 @@
|
|
|
60
61
|
"prisma": "^5.8.0",
|
|
61
62
|
"redis": "^4.6.8",
|
|
62
63
|
"redis-mock": "^0.48.0",
|
|
63
|
-
"sinon": "^17.0.1"
|
|
64
|
+
"sinon": "^17.0.1",
|
|
65
|
+
"sqlite3": "^5.1.7"
|
|
64
66
|
},
|
|
65
67
|
"browser": {
|
|
66
68
|
"cluster": false,
|