express-rate-limit 7.5.0 → 7.5.1

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/dist/index.cjs CHANGED
@@ -18,18 +18,22 @@ var __copyProps = (to, from, except, desc) => {
18
18
  var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod);
19
19
 
20
20
  // source/index.ts
21
- var source_exports = {};
22
- __export(source_exports, {
21
+ var index_exports = {};
22
+ __export(index_exports, {
23
23
  MemoryStore: () => MemoryStore,
24
24
  default: () => lib_default,
25
25
  rateLimit: () => lib_default
26
26
  });
27
- module.exports = __toCommonJS(source_exports);
27
+ module.exports = __toCommonJS(index_exports);
28
28
 
29
29
  // source/headers.ts
30
- var import_node_buffer = require("buffer");
31
- var import_node_crypto = require("crypto");
32
- var SUPPORTED_DRAFT_VERSIONS = ["draft-6", "draft-7", "draft-8"];
30
+ var import_node_buffer = require("node:buffer");
31
+ var import_node_crypto = require("node:crypto");
32
+ var SUPPORTED_DRAFT_VERSIONS = [
33
+ "draft-6",
34
+ "draft-7",
35
+ "draft-8"
36
+ ];
33
37
  var getResetSeconds = (resetTime, windowMs) => {
34
38
  let resetSeconds = void 0;
35
39
  if (resetTime) {
@@ -47,8 +51,7 @@ var getPartitionKey = (key) => {
47
51
  return import_node_buffer.Buffer.from(partitionKey).toString("base64");
48
52
  };
49
53
  var setLegacyHeaders = (response, info) => {
50
- if (response.headersSent)
51
- return;
54
+ if (response.headersSent) return;
52
55
  response.setHeader("X-RateLimit-Limit", info.limit.toString());
53
56
  response.setHeader("X-RateLimit-Remaining", info.remaining.toString());
54
57
  if (info.resetTime instanceof Date) {
@@ -60,8 +63,7 @@ var setLegacyHeaders = (response, info) => {
60
63
  }
61
64
  };
62
65
  var setDraft6Headers = (response, info, windowMs) => {
63
- if (response.headersSent)
64
- return;
66
+ if (response.headersSent) return;
65
67
  const windowSeconds = Math.ceil(windowMs / 1e3);
66
68
  const resetSeconds = getResetSeconds(info.resetTime);
67
69
  response.setHeader("RateLimit-Policy", `${info.limit};w=${windowSeconds}`);
@@ -71,8 +73,7 @@ var setDraft6Headers = (response, info, windowMs) => {
71
73
  response.setHeader("RateLimit-Reset", resetSeconds.toString());
72
74
  };
73
75
  var setDraft7Headers = (response, info, windowMs) => {
74
- if (response.headersSent)
75
- return;
76
+ if (response.headersSent) return;
76
77
  const windowSeconds = Math.ceil(windowMs / 1e3);
77
78
  const resetSeconds = getResetSeconds(info.resetTime, windowMs);
78
79
  response.setHeader("RateLimit-Policy", `${info.limit};w=${windowSeconds}`);
@@ -82,8 +83,7 @@ var setDraft7Headers = (response, info, windowMs) => {
82
83
  );
83
84
  };
84
85
  var setDraft8Headers = (response, info, windowMs, name, key) => {
85
- if (response.headersSent)
86
- return;
86
+ if (response.headersSent) return;
87
87
  const windowSeconds = Math.ceil(windowMs / 1e3);
88
88
  const resetSeconds = getResetSeconds(info.resetTime, windowMs);
89
89
  const partitionKey = getPartitionKey(key);
@@ -93,14 +93,13 @@ var setDraft8Headers = (response, info, windowMs, name, key) => {
93
93
  response.append("RateLimit", `"${name}"; ${header}`);
94
94
  };
95
95
  var setRetryAfterHeader = (response, info, windowMs) => {
96
- if (response.headersSent)
97
- return;
96
+ if (response.headersSent) return;
98
97
  const resetSeconds = getResetSeconds(info.resetTime, windowMs);
99
98
  response.setHeader("Retry-After", resetSeconds.toString());
100
99
  };
101
100
 
102
101
  // source/validations.ts
103
- var import_node_net = require("net");
102
+ var import_node_net = require("node:net");
104
103
  var ValidationError = class extends Error {
105
104
  /**
106
105
  * The code must be a string, in snake case and all capital, that starts with
@@ -128,8 +127,7 @@ var validations = {
128
127
  },
129
128
  // Should be EnabledValidations type, but that's a circular reference
130
129
  disable() {
131
- for (const k of Object.keys(this.enabled))
132
- this.enabled[k] = false;
130
+ for (const k of Object.keys(this.enabled)) this.enabled[k] = false;
133
131
  },
134
132
  /**
135
133
  * Checks whether the IP address is valid, and that it does not have a port
@@ -302,7 +300,8 @@ var validations = {
302
300
  * @returns {void}
303
301
  */
304
302
  headersDraftVersion(version) {
305
- if (typeof version !== "string" || !SUPPORTED_DRAFT_VERSIONS.includes(version)) {
303
+ if (typeof version !== "string" || // @ts-expect-error This is fine. If version is not in the array, it will just return false.
304
+ !SUPPORTED_DRAFT_VERSIONS.includes(version)) {
306
305
  const versionString = SUPPORTED_DRAFT_VERSIONS.join(", ");
307
306
  throw new ValidationError(
308
307
  "ERR_ERL_HEADERS_UNSUPPORTED_DRAFT_VERSION",
@@ -400,10 +399,8 @@ var getValidations = (_enabled) => {
400
399
  args
401
400
  );
402
401
  } catch (error) {
403
- if (error instanceof ChangeWarning)
404
- console.warn(error);
405
- else
406
- console.error(error);
402
+ if (error instanceof ChangeWarning) console.warn(error);
403
+ else console.error(error);
407
404
  }
408
405
  };
409
406
  }
@@ -438,13 +435,11 @@ var MemoryStore = class {
438
435
  */
439
436
  init(options) {
440
437
  this.windowMs = options.windowMs;
441
- if (this.interval)
442
- clearInterval(this.interval);
438
+ if (this.interval) clearInterval(this.interval);
443
439
  this.interval = setInterval(() => {
444
440
  this.clearExpired();
445
441
  }, this.windowMs);
446
- if (this.interval.unref)
447
- this.interval.unref();
442
+ if (this.interval.unref) this.interval.unref();
448
443
  }
449
444
  /**
450
445
  * Method to fetch a client's hit count and reset time.
@@ -485,8 +480,7 @@ var MemoryStore = class {
485
480
  */
486
481
  async decrement(key) {
487
482
  const client = this.getClient(key);
488
- if (client.totalHits > 0)
489
- client.totalHits--;
483
+ if (client.totalHits > 0) client.totalHits--;
490
484
  }
491
485
  /**
492
486
  * Method to reset a client's hit counter.
@@ -544,8 +538,7 @@ var MemoryStore = class {
544
538
  * @returns {Client} - The requested client.
545
539
  */
546
540
  getClient(key) {
547
- if (this.current.has(key))
548
- return this.current.get(key);
541
+ if (this.current.has(key)) return this.current.get(key);
549
542
  let client;
550
543
  if (this.previous.has(key)) {
551
544
  client = this.previous.get(key);
@@ -585,8 +578,7 @@ var promisifyStore = (passedStore) => {
585
578
  legacyStore.incr(
586
579
  key,
587
580
  (error, totalHits, resetTime) => {
588
- if (error)
589
- reject(error);
581
+ if (error) reject(error);
590
582
  resolve({ totalHits, resetTime });
591
583
  }
592
584
  );
@@ -633,8 +625,7 @@ var parseOptions = (passedOptions) => {
633
625
  );
634
626
  validations2.onLimitReached(notUndefinedOptions.onLimitReached);
635
627
  let standardHeaders = notUndefinedOptions.standardHeaders ?? false;
636
- if (standardHeaders === true)
637
- standardHeaders = "draft-6";
628
+ if (standardHeaders === true) standardHeaders = "draft-6";
638
629
  const config = {
639
630
  windowMs: 60 * 1e3,
640
631
  limit: passedOptions.max ?? 5,
@@ -650,14 +641,10 @@ var parseOptions = (passedOptions) => {
650
641
  const minutes = config.windowMs / (1e3 * 60);
651
642
  const hours = config.windowMs / (1e3 * 60 * 60);
652
643
  const days = config.windowMs / (1e3 * 60 * 60 * 24);
653
- if (seconds < 60)
654
- duration = `${seconds}sec`;
655
- else if (minutes < 60)
656
- duration = `${minutes}min`;
657
- else if (hours < 24)
658
- duration = `${hours}hr${hours > 1 ? "s" : ""}`;
659
- else
660
- duration = `${days}day${days > 1 ? "s" : ""}`;
644
+ if (seconds < 60) duration = `${seconds}sec`;
645
+ else if (minutes < 60) duration = `${minutes}min`;
646
+ else if (hours < 24) duration = `${hours}hr${hours > 1 ? "s" : ""}`;
647
+ else duration = `${days}day${days > 1 ? "s" : ""}`;
661
648
  return `${limit}-in-${duration}`;
662
649
  },
663
650
  requestPropertyName: "rateLimit",
@@ -682,12 +669,12 @@ var parseOptions = (passedOptions) => {
682
669
  }
683
670
  },
684
671
  passOnStoreError: false,
685
- // Allow the default options to be overriden by the passed options.
672
+ // Allow the default options to be overridden by the passed options.
686
673
  ...notUndefinedOptions,
687
674
  // `standardHeaders` is resolved into a draft version above, use that.
688
675
  standardHeaders,
689
676
  // Note that this field is declared after the user's options are spread in,
690
- // so that this field doesn't get overriden with an un-promisified store!
677
+ // so that this field doesn't get overridden with an un-promisified store!
691
678
  store: promisifyStore(notUndefinedOptions.store ?? new MemoryStore()),
692
679
  // Print an error to the console if a few known misconfigurations are detected.
693
680
  validations: validations2
@@ -711,8 +698,7 @@ var rateLimit = (passedOptions) => {
711
698
  const options = getOptionsFromConfig(config);
712
699
  config.validations.creationStack(config.store);
713
700
  config.validations.unsharedStore(config.store);
714
- if (typeof config.store.init === "function")
715
- config.store.init(options);
701
+ if (typeof config.store.init === "function") config.store.init(options);
716
702
  const middleware = handleAsyncErrors(
717
703
  async (request, response, next) => {
718
704
  const skip = await config.skip(request, response);
@@ -797,8 +783,7 @@ var rateLimit = (passedOptions) => {
797
783
  await decrementKey();
798
784
  });
799
785
  response.on("close", async () => {
800
- if (!response.writableEnded)
801
- await decrementKey();
786
+ if (!response.writableEnded) await decrementKey();
802
787
  });
803
788
  response.on("error", async () => {
804
789
  await decrementKey();
package/dist/index.d.cts CHANGED
@@ -119,7 +119,11 @@ declare const validations: {
119
119
  creationStack(store: Store): void;
120
120
  };
121
121
  export type Validations = typeof validations;
122
- declare const SUPPORTED_DRAFT_VERSIONS: string[];
122
+ declare const SUPPORTED_DRAFT_VERSIONS: readonly [
123
+ "draft-6",
124
+ "draft-7",
125
+ "draft-8"
126
+ ];
123
127
  /**
124
128
  * Callback that fires when a client's hit counter is incremented.
125
129
  *
package/dist/index.d.mts CHANGED
@@ -119,7 +119,11 @@ declare const validations: {
119
119
  creationStack(store: Store): void;
120
120
  };
121
121
  export type Validations = typeof validations;
122
- declare const SUPPORTED_DRAFT_VERSIONS: string[];
122
+ declare const SUPPORTED_DRAFT_VERSIONS: readonly [
123
+ "draft-6",
124
+ "draft-7",
125
+ "draft-8"
126
+ ];
123
127
  /**
124
128
  * Callback that fires when a client's hit counter is incremented.
125
129
  *
package/dist/index.d.ts CHANGED
@@ -119,7 +119,11 @@ declare const validations: {
119
119
  creationStack(store: Store): void;
120
120
  };
121
121
  export type Validations = typeof validations;
122
- declare const SUPPORTED_DRAFT_VERSIONS: string[];
122
+ declare const SUPPORTED_DRAFT_VERSIONS: readonly [
123
+ "draft-6",
124
+ "draft-7",
125
+ "draft-8"
126
+ ];
123
127
  /**
124
128
  * Callback that fires when a client's hit counter is incremented.
125
129
  *
package/dist/index.mjs CHANGED
@@ -1,7 +1,11 @@
1
1
  // source/headers.ts
2
- import { Buffer } from "buffer";
3
- import { createHash } from "crypto";
4
- var SUPPORTED_DRAFT_VERSIONS = ["draft-6", "draft-7", "draft-8"];
2
+ import { Buffer } from "node:buffer";
3
+ import { createHash } from "node:crypto";
4
+ var SUPPORTED_DRAFT_VERSIONS = [
5
+ "draft-6",
6
+ "draft-7",
7
+ "draft-8"
8
+ ];
5
9
  var getResetSeconds = (resetTime, windowMs) => {
6
10
  let resetSeconds = void 0;
7
11
  if (resetTime) {
@@ -19,8 +23,7 @@ var getPartitionKey = (key) => {
19
23
  return Buffer.from(partitionKey).toString("base64");
20
24
  };
21
25
  var setLegacyHeaders = (response, info) => {
22
- if (response.headersSent)
23
- return;
26
+ if (response.headersSent) return;
24
27
  response.setHeader("X-RateLimit-Limit", info.limit.toString());
25
28
  response.setHeader("X-RateLimit-Remaining", info.remaining.toString());
26
29
  if (info.resetTime instanceof Date) {
@@ -32,8 +35,7 @@ var setLegacyHeaders = (response, info) => {
32
35
  }
33
36
  };
34
37
  var setDraft6Headers = (response, info, windowMs) => {
35
- if (response.headersSent)
36
- return;
38
+ if (response.headersSent) return;
37
39
  const windowSeconds = Math.ceil(windowMs / 1e3);
38
40
  const resetSeconds = getResetSeconds(info.resetTime);
39
41
  response.setHeader("RateLimit-Policy", `${info.limit};w=${windowSeconds}`);
@@ -43,8 +45,7 @@ var setDraft6Headers = (response, info, windowMs) => {
43
45
  response.setHeader("RateLimit-Reset", resetSeconds.toString());
44
46
  };
45
47
  var setDraft7Headers = (response, info, windowMs) => {
46
- if (response.headersSent)
47
- return;
48
+ if (response.headersSent) return;
48
49
  const windowSeconds = Math.ceil(windowMs / 1e3);
49
50
  const resetSeconds = getResetSeconds(info.resetTime, windowMs);
50
51
  response.setHeader("RateLimit-Policy", `${info.limit};w=${windowSeconds}`);
@@ -54,8 +55,7 @@ var setDraft7Headers = (response, info, windowMs) => {
54
55
  );
55
56
  };
56
57
  var setDraft8Headers = (response, info, windowMs, name, key) => {
57
- if (response.headersSent)
58
- return;
58
+ if (response.headersSent) return;
59
59
  const windowSeconds = Math.ceil(windowMs / 1e3);
60
60
  const resetSeconds = getResetSeconds(info.resetTime, windowMs);
61
61
  const partitionKey = getPartitionKey(key);
@@ -65,14 +65,13 @@ var setDraft8Headers = (response, info, windowMs, name, key) => {
65
65
  response.append("RateLimit", `"${name}"; ${header}`);
66
66
  };
67
67
  var setRetryAfterHeader = (response, info, windowMs) => {
68
- if (response.headersSent)
69
- return;
68
+ if (response.headersSent) return;
70
69
  const resetSeconds = getResetSeconds(info.resetTime, windowMs);
71
70
  response.setHeader("Retry-After", resetSeconds.toString());
72
71
  };
73
72
 
74
73
  // source/validations.ts
75
- import { isIP } from "net";
74
+ import { isIP } from "node:net";
76
75
  var ValidationError = class extends Error {
77
76
  /**
78
77
  * The code must be a string, in snake case and all capital, that starts with
@@ -100,8 +99,7 @@ var validations = {
100
99
  },
101
100
  // Should be EnabledValidations type, but that's a circular reference
102
101
  disable() {
103
- for (const k of Object.keys(this.enabled))
104
- this.enabled[k] = false;
102
+ for (const k of Object.keys(this.enabled)) this.enabled[k] = false;
105
103
  },
106
104
  /**
107
105
  * Checks whether the IP address is valid, and that it does not have a port
@@ -274,7 +272,8 @@ var validations = {
274
272
  * @returns {void}
275
273
  */
276
274
  headersDraftVersion(version) {
277
- if (typeof version !== "string" || !SUPPORTED_DRAFT_VERSIONS.includes(version)) {
275
+ if (typeof version !== "string" || // @ts-expect-error This is fine. If version is not in the array, it will just return false.
276
+ !SUPPORTED_DRAFT_VERSIONS.includes(version)) {
278
277
  const versionString = SUPPORTED_DRAFT_VERSIONS.join(", ");
279
278
  throw new ValidationError(
280
279
  "ERR_ERL_HEADERS_UNSUPPORTED_DRAFT_VERSION",
@@ -372,10 +371,8 @@ var getValidations = (_enabled) => {
372
371
  args
373
372
  );
374
373
  } catch (error) {
375
- if (error instanceof ChangeWarning)
376
- console.warn(error);
377
- else
378
- console.error(error);
374
+ if (error instanceof ChangeWarning) console.warn(error);
375
+ else console.error(error);
379
376
  }
380
377
  };
381
378
  }
@@ -410,13 +407,11 @@ var MemoryStore = class {
410
407
  */
411
408
  init(options) {
412
409
  this.windowMs = options.windowMs;
413
- if (this.interval)
414
- clearInterval(this.interval);
410
+ if (this.interval) clearInterval(this.interval);
415
411
  this.interval = setInterval(() => {
416
412
  this.clearExpired();
417
413
  }, this.windowMs);
418
- if (this.interval.unref)
419
- this.interval.unref();
414
+ if (this.interval.unref) this.interval.unref();
420
415
  }
421
416
  /**
422
417
  * Method to fetch a client's hit count and reset time.
@@ -457,8 +452,7 @@ var MemoryStore = class {
457
452
  */
458
453
  async decrement(key) {
459
454
  const client = this.getClient(key);
460
- if (client.totalHits > 0)
461
- client.totalHits--;
455
+ if (client.totalHits > 0) client.totalHits--;
462
456
  }
463
457
  /**
464
458
  * Method to reset a client's hit counter.
@@ -516,8 +510,7 @@ var MemoryStore = class {
516
510
  * @returns {Client} - The requested client.
517
511
  */
518
512
  getClient(key) {
519
- if (this.current.has(key))
520
- return this.current.get(key);
513
+ if (this.current.has(key)) return this.current.get(key);
521
514
  let client;
522
515
  if (this.previous.has(key)) {
523
516
  client = this.previous.get(key);
@@ -557,8 +550,7 @@ var promisifyStore = (passedStore) => {
557
550
  legacyStore.incr(
558
551
  key,
559
552
  (error, totalHits, resetTime) => {
560
- if (error)
561
- reject(error);
553
+ if (error) reject(error);
562
554
  resolve({ totalHits, resetTime });
563
555
  }
564
556
  );
@@ -605,8 +597,7 @@ var parseOptions = (passedOptions) => {
605
597
  );
606
598
  validations2.onLimitReached(notUndefinedOptions.onLimitReached);
607
599
  let standardHeaders = notUndefinedOptions.standardHeaders ?? false;
608
- if (standardHeaders === true)
609
- standardHeaders = "draft-6";
600
+ if (standardHeaders === true) standardHeaders = "draft-6";
610
601
  const config = {
611
602
  windowMs: 60 * 1e3,
612
603
  limit: passedOptions.max ?? 5,
@@ -622,14 +613,10 @@ var parseOptions = (passedOptions) => {
622
613
  const minutes = config.windowMs / (1e3 * 60);
623
614
  const hours = config.windowMs / (1e3 * 60 * 60);
624
615
  const days = config.windowMs / (1e3 * 60 * 60 * 24);
625
- if (seconds < 60)
626
- duration = `${seconds}sec`;
627
- else if (minutes < 60)
628
- duration = `${minutes}min`;
629
- else if (hours < 24)
630
- duration = `${hours}hr${hours > 1 ? "s" : ""}`;
631
- else
632
- duration = `${days}day${days > 1 ? "s" : ""}`;
616
+ if (seconds < 60) duration = `${seconds}sec`;
617
+ else if (minutes < 60) duration = `${minutes}min`;
618
+ else if (hours < 24) duration = `${hours}hr${hours > 1 ? "s" : ""}`;
619
+ else duration = `${days}day${days > 1 ? "s" : ""}`;
633
620
  return `${limit}-in-${duration}`;
634
621
  },
635
622
  requestPropertyName: "rateLimit",
@@ -654,12 +641,12 @@ var parseOptions = (passedOptions) => {
654
641
  }
655
642
  },
656
643
  passOnStoreError: false,
657
- // Allow the default options to be overriden by the passed options.
644
+ // Allow the default options to be overridden by the passed options.
658
645
  ...notUndefinedOptions,
659
646
  // `standardHeaders` is resolved into a draft version above, use that.
660
647
  standardHeaders,
661
648
  // Note that this field is declared after the user's options are spread in,
662
- // so that this field doesn't get overriden with an un-promisified store!
649
+ // so that this field doesn't get overridden with an un-promisified store!
663
650
  store: promisifyStore(notUndefinedOptions.store ?? new MemoryStore()),
664
651
  // Print an error to the console if a few known misconfigurations are detected.
665
652
  validations: validations2
@@ -683,8 +670,7 @@ var rateLimit = (passedOptions) => {
683
670
  const options = getOptionsFromConfig(config);
684
671
  config.validations.creationStack(config.store);
685
672
  config.validations.unsharedStore(config.store);
686
- if (typeof config.store.init === "function")
687
- config.store.init(options);
673
+ if (typeof config.store.init === "function") config.store.init(options);
688
674
  const middleware = handleAsyncErrors(
689
675
  async (request, response, next) => {
690
676
  const skip = await config.skip(request, response);
@@ -769,8 +755,7 @@ var rateLimit = (passedOptions) => {
769
755
  await decrementKey();
770
756
  });
771
757
  response.on("close", async () => {
772
- if (!response.writableEnded)
773
- await decrementKey();
758
+ if (!response.writableEnded) await decrementKey();
774
759
  });
775
760
  response.on("error", async () => {
776
761
  await decrementKey();
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "express-rate-limit",
3
- "version": "7.5.0",
3
+ "version": "7.5.1",
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",
@@ -74,7 +74,7 @@
74
74
  "prepare": "run-s compile && husky install config/husky"
75
75
  },
76
76
  "peerDependencies": {
77
- "express": "^4.11 || 5 || ^5.0.0-beta.1"
77
+ "express": ">= 4.11"
78
78
  },
79
79
  "devDependencies": {
80
80
  "@express-rate-limit/prettier": "1.1.1",
@@ -86,7 +86,7 @@
86
86
  "@types/supertest": "2.0.15",
87
87
  "del-cli": "5.1.0",
88
88
  "dts-bundle-generator": "8.0.1",
89
- "esbuild": "0.19.5",
89
+ "esbuild": "0.25.0",
90
90
  "express": "4.21.1",
91
91
  "husky": "8.0.3",
92
92
  "jest": "29.7.0",