express-rate-limit 6.1.0 → 6.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/changelog.md CHANGED
@@ -6,6 +6,19 @@ The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/),
6
6
  and this project adheres to
7
7
  [Semantic Versioning](https://semver.org/spec/v2.0.0.html).
8
8
 
9
+ ## [6.2.0](https://github.com/nfriedly/express-rate-limit/releases/tag/v6.2.0)
10
+
11
+ ### Added
12
+
13
+ - Export the `MemoryStore`, so it can now be imported as a named import
14
+ (`import { MemoryStore } from 'express-rate-limit'`).
15
+
16
+ ### Fixed
17
+
18
+ - Deprecate the `onLimitReached` option (this was supposed to be deprecated in
19
+ v6.0.0 itself); developers should use a custom handler function that checks if
20
+ the rate limit has been exceeded instead.
21
+
9
22
  ## [6.1.0](https://github.com/nfriedly/express-rate-limit/releases/tag/v6.1.0)
10
23
 
11
24
  ### Added
package/dist/index.cjs CHANGED
@@ -24,6 +24,7 @@ var __toCommonJS = /* @__PURE__ */ ((cache) => {
24
24
  // source/index.ts
25
25
  var source_exports = {};
26
26
  __export(source_exports, {
27
+ MemoryStore: () => MemoryStore,
27
28
  default: () => lib_default,
28
29
  rateLimit: () => lib_default
29
30
  });
@@ -221,4 +222,4 @@ var rateLimit = (passedOptions) => {
221
222
  };
222
223
  var lib_default = rateLimit;
223
224
  module.exports = __toCommonJS(source_exports);
224
- module.exports = rateLimit; module.exports.default = rateLimit; module.exports.rateLimit = rateLimit;
225
+ module.exports = rateLimit; module.exports.default = rateLimit; module.exports.rateLimit = rateLimit; module.exports.MemoryStore = MemoryStore;
package/dist/index.d.ts CHANGED
@@ -5,29 +5,29 @@ import { NextFunction, Request, RequestHandler, Response } from 'express';
5
5
  /**
6
6
  * Callback that fires when a client's hit counter is incremented.
7
7
  *
8
- * @param error {Error | undefined} - The error that occurred, if any
9
- * @param totalHits {number} - The number of hits for that client so far
10
- * @param resetTime {Date | undefined} - The time when the counter resets
8
+ * @param error {Error | undefined} - The error that occurred, if any.
9
+ * @param totalHits {number} - The number of hits for that client so far.
10
+ * @param resetTime {Date | undefined} - The time when the counter resets.
11
11
  */
12
12
  export declare type IncrementCallback = (error: Error | undefined, totalHits: number, resetTime: Date | undefined) => void;
13
13
  /**
14
14
  * Method (in the form of middleware) to generate/retrieve a value based on the
15
- * incoming request
15
+ * incoming request.
16
16
  *
17
- * @param request {Request} - The Express request object
18
- * @param response {Response} - The Express response object
17
+ * @param request {Request} - The Express request object.
18
+ * @param response {Response} - The Express response object.
19
19
  *
20
- * @returns {T} - The value needed
20
+ * @returns {T} - The value needed.
21
21
  */
22
22
  export declare type ValueDeterminingMiddleware<T> = (request: Request, response: Response) => T | Promise<T>;
23
23
  /**
24
24
  * Express request handler that sends back a response when a client is
25
25
  * rate-limited.
26
26
  *
27
- * @param request {Request} - The Express request object
28
- * @param response {Response} - The Express response object
29
- * @param next {NextFunction} - The Express `next` function, can be called to skip responding
30
- * @param optionsUsed {Options} - The options used to set up the middleware
27
+ * @param request {Request} - The Express request object.
28
+ * @param response {Response} - The Express response object.
29
+ * @param next {NextFunction} - The Express `next` function, can be called to skip responding.
30
+ * @param optionsUsed {Options} - The options used to set up the middleware.
31
31
  */
32
32
  export declare type RateLimitExceededEventHandler = (request: Request, response: Response, next: NextFunction, optionsUsed: Options) => void;
33
33
  /**
@@ -35,16 +35,16 @@ export declare type RateLimitExceededEventHandler = (request: Request, response:
35
35
  * but not for subsequent requests. May be used for logging, etc. Should *not*
36
36
  * send a response.
37
37
  *
38
- * @param request {Request} - The Express request object
39
- * @param response {Response} - The Express response object
40
- * @param optionsUsed {Options} - The options used to set up the middleware
38
+ * @param request {Request} - The Express request object.
39
+ * @param response {Response} - The Express response object.
40
+ * @param optionsUsed {Options} - The options used to set up the middleware.
41
41
  */
42
42
  export declare type RateLimitReachedEventHandler = (request: Request, response: Response, optionsUsed: Options) => void;
43
43
  /**
44
44
  * Data returned from the `Store` when a client's hit counter is incremented.
45
45
  *
46
- * @property totalHits {number} - The number of hits for that client so far
47
- * @property resetTime {Date | undefined} - The time when the counter resets
46
+ * @property totalHits {number} - The number of hits for that client so far.
47
+ * @property resetTime {Date | undefined} - The time when the counter resets.
48
48
  */
49
49
  export declare type IncrementResponse = {
50
50
  totalHits: number;
@@ -57,7 +57,7 @@ export declare type RateLimitRequestHandler = RequestHandler & {
57
57
  /**
58
58
  * Method to reset a client's hit counter.
59
59
  *
60
- * @param key {string} - The identifier for a client
60
+ * @param key {string} - The identifier for a client.
61
61
  */
62
62
  resetKey: (key: string) => void;
63
63
  };
@@ -70,20 +70,20 @@ export interface LegacyStore {
70
70
  /**
71
71
  * Method to increment a client's hit counter.
72
72
  *
73
- * @param key {string} - The identifier for a client
74
- * @param callback {IncrementCallback} - The callback to call once the counter is incremented
73
+ * @param key {string} - The identifier for a client.
74
+ * @param callback {IncrementCallback} - The callback to call once the counter is incremented.
75
75
  */
76
76
  incr: (key: string, callback: IncrementCallback) => void;
77
77
  /**
78
78
  * Method to decrement a client's hit counter.
79
79
  *
80
- * @param key {string} - The identifier for a client
80
+ * @param key {string} - The identifier for a client.
81
81
  */
82
82
  decrement: (key: string) => void;
83
83
  /**
84
84
  * Method to reset a client's hit counter.
85
85
  *
86
- * @param key {string} - The identifier for a client
86
+ * @param key {string} - The identifier for a client.
87
87
  */
88
88
  resetKey: (key: string) => void;
89
89
  /**
@@ -99,27 +99,27 @@ export interface Store {
99
99
  * Method that initializes the store, and has access to the options passed to
100
100
  * the middleware too.
101
101
  *
102
- * @param options {Options} - The options used to setup the middleware
102
+ * @param options {Options} - The options used to setup the middleware.
103
103
  */
104
104
  init?: (options: Options) => void;
105
105
  /**
106
106
  * Method to increment a client's hit counter.
107
107
  *
108
- * @param key {string} - The identifier for a client
108
+ * @param key {string} - The identifier for a client.
109
109
  *
110
- * @returns {IncrementResponse} - The number of hits and reset time for that client
110
+ * @returns {IncrementResponse} - The number of hits and reset time for that client.
111
111
  */
112
112
  increment: (key: string) => Promise<IncrementResponse> | IncrementResponse;
113
113
  /**
114
114
  * Method to decrement a client's hit counter.
115
115
  *
116
- * @param key {string} - The identifier for a client
116
+ * @param key {string} - The identifier for a client.
117
117
  */
118
118
  decrement: (key: string) => Promise<void> | void;
119
119
  /**
120
120
  * Method to reset a client's hit counter.
121
121
  *
122
- * @param key {string} - The identifier for a client
122
+ * @param key {string} - The identifier for a client.
123
123
  */
124
124
  resetKey: (key: string) => Promise<void> | void;
125
125
  /**
@@ -133,18 +133,24 @@ export interface Store {
133
133
  export interface Options {
134
134
  /**
135
135
  * How long we should remember the requests.
136
+ *
137
+ * Defaults to `60000` ms (= 1 minute).
136
138
  */
137
139
  readonly windowMs: number;
138
140
  /**
139
- * The maximum number of connection to allow during the `window` before
141
+ * The maximum number of connections to allow during the `window` before
140
142
  * rate limiting the client.
141
143
  *
142
144
  * Can be the limit itself as a number or express middleware that parses
143
145
  * the request and then figures out the limit.
146
+ *
147
+ * Defaults to `5`.
144
148
  */
145
149
  readonly max: number | ValueDeterminingMiddleware<number>;
146
150
  /**
147
151
  * The response body to send back when a client is rate limited.
152
+ *
153
+ * Defaults to `'Too many requests, please try again later.'`
148
154
  */
149
155
  readonly message: any;
150
156
  /**
@@ -156,10 +162,14 @@ export interface Options {
156
162
  /**
157
163
  * Whether to send `X-RateLimit-*` headers with the rate limit and the number
158
164
  * of requests.
165
+ *
166
+ * Defaults to `true` (for backward compatibility).
159
167
  */
160
168
  readonly legacyHeaders: boolean;
161
169
  /**
162
- * Whether to enable support for the rate limit standardization headers (`RateLimit-*`).
170
+ * Whether to enable support for the standardized rate limit headers (`RateLimit-*`).
171
+ *
172
+ * Defaults to `false` (for backward compatibility, but its use is recommended).
163
173
  */
164
174
  readonly standardHeaders: boolean;
165
175
  /**
@@ -171,41 +181,57 @@ export interface Options {
171
181
  /**
172
182
  * If `true`, the library will (by default) skip all requests that have a 4XX
173
183
  * or 5XX status.
184
+ *
185
+ * Defaults to `false`.
174
186
  */
175
187
  readonly skipFailedRequests: boolean;
176
188
  /**
177
189
  * If `true`, the library will (by default) skip all requests that have a
178
190
  * status code less than 400.
191
+ *
192
+ * Defaults to `false`.
179
193
  */
180
194
  readonly skipSuccessfulRequests: boolean;
181
- /**
182
- * Method to determine whether or not the request counts as 'succesful'. Used
183
- * when either `skipSuccessfulRequests` or `skipFailedRequests` is set to true.
184
- */
185
- readonly requestWasSuccessful: ValueDeterminingMiddleware<boolean>;
186
195
  /**
187
196
  * Method to generate custom identifiers for clients.
188
197
  *
189
198
  * By default, the client's IP address is used.
190
199
  */
191
200
  readonly keyGenerator: ValueDeterminingMiddleware<string>;
192
- /**
193
- * Method (in the form of middleware) to determine whether or not this request
194
- * counts towards a client's quota.
195
- */
196
- readonly skip: ValueDeterminingMiddleware<boolean>;
197
201
  /**
198
202
  * Express request handler that sends back a response when a client is
199
203
  * rate-limited.
204
+ *
205
+ * By default, sends back the `statusCode` and `message` set via the options.
200
206
  */
201
207
  readonly handler: RateLimitExceededEventHandler;
202
208
  /**
203
209
  * Express request handler that sends back a response when a client has
204
210
  * reached their rate limit, and will be rate limited on their next request.
211
+ *
212
+ * @deprecated 6.x - Please use a custom `handler` that checks the number of
213
+ * hits instead.
205
214
  */
206
215
  readonly onLimitReached: RateLimitReachedEventHandler;
207
216
  /**
208
- * The {@link Store} to use to store the hit count for each client.
217
+ * Method (in the form of middleware) to determine whether or not this request
218
+ * counts towards a client's quota.
219
+ *
220
+ * By default, skips no requests.
221
+ */
222
+ readonly skip: ValueDeterminingMiddleware<boolean>;
223
+ /**
224
+ * Method to determine whether or not the request counts as 'succesful'. Used
225
+ * when either `skipSuccessfulRequests` or `skipFailedRequests` is set to true.
226
+ *
227
+ * By default, requests with a response status code less than 400 are considered
228
+ * successful.
229
+ */
230
+ readonly requestWasSuccessful: ValueDeterminingMiddleware<boolean>;
231
+ /**
232
+ * The `Store` to use to store the hit count for each client.
233
+ *
234
+ * By default, the built-in `MemoryStore` will be used.
209
235
  */
210
236
  store: Store;
211
237
  /**
@@ -244,15 +270,74 @@ export interface RateLimitInfo {
244
270
  *
245
271
  * Create an instance of IP rate-limiting middleware for Express.
246
272
  *
247
- * @param passedOptions {Options} - Options to configure the rate limiter
273
+ * @param passedOptions {Options} - Options to configure the rate limiter.
248
274
  *
249
- * @returns {RateLimitRequestHandler} - The middleware that rate-limits clients based on your configuration
275
+ * @returns {RateLimitRequestHandler} - The middleware that rate-limits clients based on your configuration.
250
276
  *
251
277
  * @public
252
278
  */
253
279
  export declare const rateLimit: (passedOptions?: (Omit<Partial<Options>, "store"> & {
254
280
  store?: LegacyStore | Store | undefined;
255
281
  }) | undefined) => RateLimitRequestHandler;
282
+ /**
283
+ * A `Store` that stores the hit count for each client in memory.
284
+ *
285
+ * @public
286
+ */
287
+ export declare class MemoryStore implements Store {
288
+ /**
289
+ * The duration of time before which all hit counts are reset (in milliseconds).
290
+ */
291
+ windowMs: number;
292
+ /**
293
+ * The map that stores the number of hits for each client in memory.
294
+ */
295
+ hits: {
296
+ [key: string]: number | undefined;
297
+ };
298
+ /**
299
+ * The time at which all hit counts will be reset.
300
+ */
301
+ resetTime: Date;
302
+ /**
303
+ * Method that initializes the store.
304
+ *
305
+ * @param options {Options} - The options used to setup the middleware.
306
+ */
307
+ init(options: Options): void;
308
+ /**
309
+ * Method to increment a client's hit counter.
310
+ *
311
+ * @param key {string} - The identifier for a client.
312
+ *
313
+ * @returns {IncrementResponse} - The number of hits and reset time for that client.
314
+ *
315
+ * @public
316
+ */
317
+ increment(key: string): Promise<IncrementResponse>;
318
+ /**
319
+ * Method to decrement a client's hit counter.
320
+ *
321
+ * @param key {string} - The identifier for a client.
322
+ *
323
+ * @public
324
+ */
325
+ decrement(key: string): Promise<void>;
326
+ /**
327
+ * Method to reset a client's hit counter.
328
+ *
329
+ * @param key {string} - The identifier for a client.
330
+ *
331
+ * @public
332
+ */
333
+ resetKey(key: string): Promise<void>;
334
+ /**
335
+ * Method to reset everyone's hit counter.
336
+ *
337
+ * @public
338
+ */
339
+ resetAll(): Promise<void>;
340
+ }
256
341
 
257
342
  export {
258
343
  rateLimit as default,
package/dist/index.mjs CHANGED
@@ -191,6 +191,7 @@ var rateLimit = (passedOptions) => {
191
191
  };
192
192
  var lib_default = rateLimit;
193
193
  export {
194
+ MemoryStore,
194
195
  lib_default as default,
195
196
  lib_default as rateLimit
196
197
  };
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "express-rate-limit",
3
- "version": "6.1.0",
3
+ "version": "6.2.0",
4
4
  "description": "Basic IP rate-limiting middleware for Express. Use to limit repeated requests to public APIs and/or endpoints such as password reset.",
5
5
  "author": {
6
6
  "name": "Nathan Friedly",
@@ -50,7 +50,7 @@
50
50
  },
51
51
  "scripts": {
52
52
  "clean": "del-cli dist/ coverage/ *.log *.tmp *.bak *.tgz",
53
- "build:cjs": "esbuild --bundle --format=cjs --outfile=dist/index.cjs --footer:js=\"module.exports = rateLimit; module.exports.default = rateLimit; module.exports.rateLimit = rateLimit;\" source/index.ts",
53
+ "build:cjs": "esbuild --bundle --format=cjs --outfile=dist/index.cjs --footer:js=\"module.exports = rateLimit; module.exports.default = rateLimit; module.exports.rateLimit = rateLimit; module.exports.MemoryStore = MemoryStore;\" source/index.ts",
54
54
  "build:esm": "esbuild --bundle --format=esm --outfile=dist/index.mjs source/index.ts",
55
55
  "build:types": "dts-bundle-generator --out-file=dist/index.d.ts source/index.ts",
56
56
  "compile": "run-s clean build:*",
@@ -73,21 +73,21 @@
73
73
  "@jest/globals": "^27.4.6",
74
74
  "@types/express": "^4.17.13",
75
75
  "@types/jest": "^27.4.0",
76
- "@types/node": "^16.11.19",
76
+ "@types/node": "^16.11.21",
77
77
  "@types/supertest": "^2.0.11",
78
78
  "cross-env": "^7.0.3",
79
79
  "del-cli": "^4.0.1",
80
80
  "dts-bundle-generator": "^6.4.0",
81
- "esbuild": "^0.14.11",
81
+ "esbuild": "^0.14.12",
82
82
  "express": "^4.17.1",
83
83
  "husky": "^7.0.4",
84
84
  "jest": "^27.4.7",
85
- "lint-staged": "^12.1.7",
85
+ "lint-staged": "^12.2.2",
86
86
  "npm-run-all": "^4.1.5",
87
- "supertest": "^6.2.1",
88
- "ts-jest": "^27.1.1",
87
+ "supertest": "^6.2.2",
88
+ "ts-jest": "^27.1.3",
89
89
  "ts-node": "^10.4.0",
90
- "typescript": "^4.5.2",
90
+ "typescript": "^4.5.5",
91
91
  "xo": "^0.47.0"
92
92
  },
93
93
  "xo": {
package/readme.md CHANGED
@@ -22,9 +22,9 @@ This module was designed to only handle the basics and didn't even support
22
22
  external stores initially. These other options all are excellent pieces of
23
23
  software and may be more appropriate for some situations:
24
24
 
25
- - [rate-limiter-flexible](https://www.npmjs.com/package/rate-limiter-flexible)
26
- - [express-brute](https://www.npmjs.com/package/express-brute)
27
- - [rate-limiter](https://www.npmjs.com/package/express-limiter)
25
+ - [`rate-limiter-flexible`](https://www.npmjs.com/package/rate-limiter-flexible)
26
+ - [`express-brute`](https://www.npmjs.com/package/express-brute)
27
+ - [`rate-limiter`](https://www.npmjs.com/package/express-limiter)
28
28
 
29
29
  ## Installation
30
30
 
@@ -139,8 +139,7 @@ app.post('/create-account', createAccountLimiter, (request, response) => {
139
139
  To use a custom store:
140
140
 
141
141
  ```ts
142
- import rateLimit from 'express-rate-limit'
143
- import MemoryStore from 'express-rate-limit/memory-store.js'
142
+ import rateLimit, { MemoryStore } from 'express-rate-limit'
144
143
 
145
144
  const apiLimiter = rateLimit({
146
145
  windowMs: 15 * 60 * 1000, // 15 minutes
@@ -189,64 +188,55 @@ it does.
189
188
  For more information about the `trust proxy` setting, take a look at the
190
189
  [official Express documentation](https://expressjs.com/en/guide/behind-proxies.html).
191
190
 
192
- ## Request API
193
-
194
- A `request.rateLimit` property is added to all requests with the `limit`,
195
- `current`, and `remaining` number of requests and, if the store provides it, a
196
- `resetTime` Date object. These may be used in your application code to take
197
- additional actions or inform the user of their status.
198
-
199
- The property name can be configured with the configuration option
200
- `requestPropertyName`
201
-
202
- ## Configuration options
191
+ ## Configuration
203
192
 
204
193
  ### `windowMs`
205
194
 
195
+ > `number`
196
+
206
197
  Time frame for which requests are checked/remembered. Also used in the
207
198
  `Retry-After` header when the limit is reached.
208
199
 
209
- Note: with non-default stores, you may need to configure this value twice, once
210
- here and once on the store. In some cases the units also differ (e.g. seconds vs
211
- miliseconds)
200
+ Note: with stores that do not implement the `init` function (see the table in
201
+ the [`stores` section below](#stores)), you may need to configure this value
202
+ twice, once here and once on the store. In some cases the units also differ
203
+ (e.g. seconds vs miliseconds).
212
204
 
213
205
  Defaults to `60000` ms (= 1 minute).
214
206
 
215
207
  ### `max`
216
208
 
217
- Max number of connections during `windowMs` milliseconds before sending a 429
218
- response.
209
+ > `number | function`
219
210
 
220
- May be a number, or a function that returns a number or a promise. If `max` is a
221
- function, it will be called with `request` and `response` params.
211
+ The maximum number of connections to allow during the `window` before rate
212
+ limiting the client.
222
213
 
223
- Defaults to `5`. Set to `0` to disable.
214
+ Can be the limit itself as a number or a (sync/async) function that accepts the
215
+ Express `request` and `response` objects and then returns a number.
224
216
 
225
- Example of using a function:
217
+ Defaults to `5`. Set it to `0` to disable the rate limiter.
226
218
 
227
- ```ts
228
- import rateLimit from 'express-rate-limit'
219
+ An example of using a function:
229
220
 
230
- const isPremium = (request) => {
221
+ ```ts
222
+ const isPremium = async (user) => {
231
223
  // ...
232
224
  }
233
225
 
234
226
  const limiter = rateLimit({
235
- // `max` could also be an async function or return a promise
236
- max: (request, response) => {
237
- if (isPremium(request)) return 10
227
+ // ...
228
+ max: async (request, response) => {
229
+ if (await isPremium(request.user)) return 10
238
230
  else return 5
239
231
  },
240
- // ...
241
232
  })
242
-
243
- // Apply the rate limiting middleware to all requests
244
- app.use(limiter)
245
233
  ```
246
234
 
247
235
  ### `message`
248
236
 
249
- Error message sent to user when `max` is exceeded.
237
+ > `any`
238
+
239
+ The response body to send back when a client is rate limited.
250
240
 
251
241
  May be a `string`, JSON object, or any other value that Express's
252
242
  [response.send](https://expressjs.com/en/4x/api.html#response.send) method
@@ -256,240 +246,208 @@ Defaults to `'Too many requests, please try again later.'`
256
246
 
257
247
  ### `statusCode`
258
248
 
259
- HTTP status code returned when `max` is exceeded.
249
+ > `number`
250
+
251
+ The HTTP status code to send back when a client is rate limited.
260
252
 
261
- Defaults to `429`.
253
+ Defaults to `429` (HTTP 429 Too Many Requests - RFC 6585).
262
254
 
263
255
  ### `legacyHeaders`
264
256
 
265
- Enable headers for request limit (`X-RateLimit-Limit`) and current usage
266
- (`X-RateLimit-Remaining`) on all responses and time to wait before retrying
267
- (`Retry-After`) when `max` is exceeded.
257
+ > `boolean`
258
+
259
+ Whether to send the legacy rate limit headers for the limit
260
+ (`X-RateLimit-Limit`), current usage (`X-RateLimit-Remaining`) and reset time
261
+ (if the store provides it) (`X-RateLimit-Reset`) on all responses. If set to
262
+ `true`, the middleware also sends the `Retry-After` header on all blocked
263
+ requests.
268
264
 
269
- Defaults to `true`.
265
+ Defaults to `true` (for backward compatibility).
270
266
 
271
267
  > Renamed in `6.x` from `headers` to `legacyHeaders`.
272
268
 
273
269
  ### `standardHeaders`
274
270
 
275
- Enable headers conforming to the
276
- [ratelimit standardization draft](https://github.com/ietf-wg-httpapi/ratelimit-headers/blob/main/draft-ietf-httpapi-ratelimit-headers.md)
277
- adopted by the IETF: `RateLimit-Limit`, `RateLimit-Remaining`, and, if the store
278
- supports it, `RateLimit-Reset`. May be used in conjunction with, or instead of
279
- the `legacyHeaders` option.
271
+ > `boolean`
280
272
 
281
- This setting also enables the `Retry-After` header when `max` is exceeded.
273
+ Whether to enable support for headers conforming to the
274
+ [ratelimit standardization draft](https://github.com/ietf-wg-httpapi/ratelimit-headers/blob/main/draft-ietf-httpapi-ratelimit-headers.md)
275
+ adopted by the IETF (`RateLimit-Limit`, `RateLimit-Remaining`, and, if the store
276
+ supports it, `RateLimit-Reset`). If set to `true`, the middleware also sends the
277
+ `Retry-After` header on all blocked requests. May be used in conjunction with,
278
+ or instead of the `legacyHeaders` option.
282
279
 
283
- Defaults to `false` (for backward compatibility), but recommended to use.
280
+ Defaults to `false` (for backward compatibility, but its use is recommended).
284
281
 
285
282
  > Renamed in `6.x` from `draft_polli_ratelimit_headers` to `standardHeaders`.
286
283
 
287
- ### `keyGenerator`
284
+ ### `requestPropertyName`
288
285
 
289
- Function used to generate keys.
286
+ > `string`
290
287
 
291
- Defaults to `request.ip`, similar to this:
288
+ The name of the property on the Express `request` object to store the rate limit
289
+ info.
292
290
 
293
- ```ts
294
- const keyGenerator = (request /*, response*/) => request.ip
295
- ```
291
+ Defaults to `'rateLimit'`.
296
292
 
297
- ### `handler`
293
+ ### `skipFailedRequests`
294
+
295
+ > `boolean`
296
+
297
+ When set to `true`, failed requests won't be counted. Request considered failed
298
+ when the `requestWasSuccessful` option returns `false`. By default, this means
299
+ requests fail when:
300
+
301
+ - the response status >= 400
302
+ - the request was cancelled before last chunk of data was sent (response `close`
303
+ event triggered)
304
+ - the response `error` event was triggered by response
305
+
306
+ (Technically they are counted and then un-counted, so a large number of slow
307
+ requests all at once could still trigger a rate-limit. This may be fixed in a
308
+ future release. PRs welcome!)
309
+
310
+ Defaults to `false`.
311
+
312
+ ### `skipSuccessfulRequests`
313
+
314
+ > `boolean`
315
+
316
+ If `true`, the library will (by default) skip all requests that are considered
317
+ 'failed' by the `requestWasSuccessful` function. By default, this means requests
318
+ succeed when the response status code < 400.
319
+
320
+ (Technically they are counted and then un-counted, so a large number of slow
321
+ requests all at once could still trigger a rate-limit. This may be fixed in a
322
+ future release. PRs welcome!)
323
+
324
+ Defaults to `false`.
325
+
326
+ ### `keyGenerator`
298
327
 
299
- The function to handle requests once the max limit is exceeded. It receives the
300
- `request` and the `response` objects. The `next` param is available if you need
301
- to pass to the next middleware/route. Finally, the `options` param has all of
302
- the options that originally passed in when creating the current limiter and the
303
- default values for other options.
328
+ > `function`
304
329
 
305
- The `request.rateLimit` object has `limit`, `current`, and `remaining` number of
306
- requests and, if the store provides it, a `resetTime` Date object.
330
+ Method to generate custom identifiers for clients.
307
331
 
308
- Defaults to:
332
+ Should be a (sync/async) function that accepts the Express `request` and
333
+ `response` objects and then returns a string.
334
+
335
+ By default, the client's IP address is used:
309
336
 
310
337
  ```ts
311
- const handler = (request, response, next, options) => {
312
- response.status(options.statusCode).send(options.message)
313
- }
338
+ const limiter = rateLimit({
339
+ // ...
340
+ keyGenerator: (request, response) => request.ip,
341
+ })
314
342
  ```
315
343
 
316
- ### `requestWasSuccessful`
344
+ ### `handler`
317
345
 
318
- Function that is called when `skipFailedRequests` and/or
319
- `skipSuccessfulRequests` are set to `true`. May be overridden if, for example, a
320
- service sends out a 200 status code on errors.
346
+ > `function`
321
347
 
322
- Defaults to
348
+ Express request handler that sends back a response when a client is
349
+ rate-limited.
350
+
351
+ By default, sends back the `statusCode` and `message` set via the options:
323
352
 
324
353
  ```ts
325
- const requestWasSuccessful = (request, response) => response.statusCode < 400
354
+ const limiter = rateLimit({
355
+ // ...
356
+ handler: (request, response, next, options) =>
357
+ response.status(options.statusCode).send(options.message),
358
+ })
326
359
  ```
327
360
 
328
- ### `skipFailedRequests`
361
+ ### `onLimitReached`
329
362
 
330
- When set to `true`, failed requests won't be counted. Request considered failed
331
- when:
363
+ > `function`
332
364
 
333
- - response status >= 400
334
- - requests that were cancelled before last chunk of data was sent (response
335
- `close` event triggered)
336
- - response `error` event was triggered by response
365
+ A (sync/async) function that accepts the Express `request` and `response`
366
+ objects that is called when a client has reached their rate limit, and will be
367
+ rate limited on their next request.
337
368
 
338
- (Technically they are counted and then un-counted, so a large number of slow
339
- requests all at once could still trigger a rate-limit. This may be fixed in a
340
- future release.)
369
+ This method was
370
+ [deprecated in v6](https://github.com/nfriedly/express-rate-limit/releases/v6.0.0) -
371
+ Please use a custom `handler` that checks the number of hits instead.
341
372
 
342
- Defaults to `false`.
373
+ ### `skip`
343
374
 
344
- ### `skipSuccessfulRequests`
375
+ > `function`
345
376
 
346
- When set to `true` successful requests (response status < 400) won't be counted.
347
- (Technically they are counted and then un-counted, so a large number of slow
348
- requests all at once could still trigger a rate-limit. This may be fixed in a
349
- future release.)
377
+ Function to determine whether or not this request counts towards a client's
378
+ quota. Should be a (sync/async) function that accepts the Express `request` and
379
+ `response` objects and then returns `true` or `false`.
350
380
 
351
- Defaults to `false`.
381
+ Could also act as an allowlist for certain keys:
352
382
 
353
- ### `skip`
383
+ ```ts
384
+ const allowlist = ['192.168.0.56', '192.168.0.21']
354
385
 
355
- Function used to skip (whitelist) requests. Returning `true`, or a promise that
356
- resolves with `true`, from the function will skip limiting for that request.
386
+ const limiter = rateLimit({
387
+ // ...
388
+ skip: (request, response) => allowlist.includes(request.ip),
389
+ })
390
+ ```
357
391
 
358
- Defaults to always `false` (count all requests):
392
+ By default, it skips no requests:
359
393
 
360
394
  ```ts
361
- const skip = (/*request, response*/) => false
395
+ const limiter = rateLimit({
396
+ // ...
397
+ skip: (request, response) => false,
398
+ })
362
399
  ```
363
400
 
364
- ### `requestPropertyName`
401
+ ### `requestWasSuccessful`
365
402
 
366
- The name of the property that contains the rate limit information to add to the
367
- `request` object.
403
+ > `function`
368
404
 
369
- Defaults to `rateLimit`.
405
+ Method to determine whether or not the request counts as 'succesful'. Used when
406
+ either `skipSuccessfulRequests` or `skipFailedRequests` is set to true. Should
407
+ be a (sync/async) function that accepts the Express `request` and `response`
408
+ objects and then returns `true` or `false`.
409
+
410
+ By default, requests with a response status code less than 400 are considered
411
+ successful:
412
+
413
+ ```ts
414
+ const limiter = rateLimit({
415
+ // ...
416
+ requestWasSuccessful: (request, response) => response.statusCode < 400,
417
+ })
418
+ ```
370
419
 
371
420
  ### `store`
372
421
 
373
- The storage to use when persisting rate limit attempts.
422
+ > `Store`
374
423
 
375
- By default, the [memory store](source/memory-store.ts) is used.
424
+ The `Store` to use to store the hit count for each client.
376
425
 
377
- Available data stores are:
426
+ By default, the [`memory-store`](source/memory-store.ts) is used.
378
427
 
379
- - [memory-store](source/memory-store.ts): _(default)_ Simple in-memory option.
380
- Does not share state when app has multiple processes or servers.
381
- - [rate-limit-redis](https://npmjs.com/package/rate-limit-redis): A
382
- [Redis](http://redis.io/)-backed store, more suitable for large or demanding
383
- deployments.
384
- - [rate-limit-memcached](https://npmjs.org/package/rate-limit-memcached): A
385
- [Memcached](https://memcached.org/)-backed store.
386
- - [rate-limit-mongo](https://www.npmjs.com/package/rate-limit-mongo): A
387
- [MongoDB](https://www.mongodb.com/)-backed store.
388
- - [precise-memory-rate-limit](https://www.npmjs.com/package/precise-memory-rate-limit) -
389
- A memory store similar to the built-in one, except that it stores a distinct
390
- timestamp for each IP rather than bucketing them together.
428
+ Here is a list of external stores:
391
429
 
392
- You may also create your own store. It must implement the `Store` interface as
393
- follows:
430
+ | Name | Description | Legacy/Modern |
431
+ | -------------------------------------------------------------------------------------- | ----------------------------------------------------------------------------------------------------- | ------------------- |
432
+ | [`memory-store`](source/memory-store.ts) | _(default)_ Simple in-memory option. Does not share state when app has multiple processes or servers. | Modern as of v6.0.0 |
433
+ | [`rate-limit-redis`](https://npmjs.com/package/rate-limit-redis) | A [Redis](http://redis.io/)-backed store, more suitable for large or demanding deployments. | Modern as of v3.0.0 |
434
+ | [`rate-limit-memcached`](https://npmjs.org/package/rate-limit-memcached) | A [Memcached](https://memcached.org/)-backed store. | Legacy |
435
+ | [`rate-limit-mongo`](https://www.npmjs.com/package/rate-limit-mongo) | A [MongoDB](https://www.mongodb.com/)-backed store. | Legacy |
436
+ | [`precise-memory-rate-limit`](https://www.npmjs.com/package/precise-memory-rate-limit) | A memory store similar to the built-in one, except that it stores a distinct timestamp for each key. | Legacy |
394
437
 
395
- ```ts
396
- import rateLimit, {
397
- Store,
398
- Options,
399
- IncrementResponse,
400
- } from 'express-rate-limit'
401
-
402
- /**
403
- * A {@link Store} that stores the hit count for each client.
404
- *
405
- * @public
406
- */
407
- class SomeStore implements Store {
408
- /**
409
- * Some store-specific parameter.
410
- */
411
- customParam!: string
412
- /**
413
- * The duration of time before which all hit counts are reset (in milliseconds).
414
- */
415
- windowMs!: number
416
-
417
- /**
418
- * @constructor for {@link SomeStore}. Only required if the user needs to pass
419
- * some store specific parameters. For example, in a Mongo Store, the user will
420
- * need to pass the URI, username and password for the Mongo database.
421
- *
422
- * @param customParam {string} - Some store-specific parameter.
423
- */
424
- constructor(customParam: string) {
425
- this.customParam = customParam
426
- }
427
-
428
- /**
429
- * Method that actually initializes the store. Must be synchronous.
430
- *
431
- * @param options {Options} - The options used to setup the middleware.
432
- *
433
- * @public
434
- */
435
- init(options: Options): void {
436
- this.windowMs = options.windowMs
437
-
438
- // ...
439
- }
440
-
441
- /**
442
- * Method to increment a client's hit counter.
443
- *
444
- * @param key {string} - The identifier for a client
445
- *
446
- * @returns {IncrementResponse} - The number of hits and reset time for that client
447
- *
448
- * @public
449
- */
450
- async increment(key: string): Promise<IncrementResponse> {
451
- // ...
452
-
453
- return {
454
- totalHits,
455
- resetTime,
456
- }
457
- }
458
-
459
- /**
460
- * Method to decrement a client's hit counter.
461
- *
462
- * @param key {string} - The identifier for a client
463
- *
464
- * @public
465
- */
466
- async decrement(key: string): Promise<void> {
467
- // ...
468
- }
469
-
470
- /**
471
- * Method to reset a client's hit counter.
472
- *
473
- * @param key {string} - The identifier for a client
474
- *
475
- * @public
476
- */
477
- async resetKey(key: string): Promise<void> {
478
- // ...
479
- }
480
-
481
- /**
482
- * Method to reset everyone's hit counter.
483
- *
484
- * @public
485
- */
486
- async resetAll(): Promise<void> {
487
- // ...
488
- }
489
- }
438
+ Take a look at
439
+ [this guide](https://github.com/nfriedly/express-rate-limit/wiki/Creating-Your-Own-Store)
440
+ if you wish to create your own store.
490
441
 
491
- export default SomeStore
492
- ```
442
+ ## Request API
443
+
444
+ A `request.rateLimit` property is added to all requests with the `limit`,
445
+ `current`, and `remaining` number of requests and, if the store provides it, a
446
+ `resetTime` Date object. These may be used in your application code to take
447
+ additional actions or inform the user of their status.
448
+
449
+ The property name can be configured with the configuration option
450
+ `requestPropertyName`.
493
451
 
494
452
  ## Instance API
495
453