express-rate-limit 7.5.1 → 8.0.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/dist/index.cjs CHANGED
@@ -1,7 +1,9 @@
1
1
  "use strict";
2
+ var __create = Object.create;
2
3
  var __defProp = Object.defineProperty;
3
4
  var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
4
5
  var __getOwnPropNames = Object.getOwnPropertyNames;
6
+ var __getProtoOf = Object.getPrototypeOf;
5
7
  var __hasOwnProp = Object.prototype.hasOwnProperty;
6
8
  var __export = (target, all) => {
7
9
  for (var name in all)
@@ -15,17 +17,196 @@ var __copyProps = (to, from, except, desc) => {
15
17
  }
16
18
  return to;
17
19
  };
20
+ var __toESM = (mod, isNodeMode, target) => (target = mod != null ? __create(__getProtoOf(mod)) : {}, __copyProps(
21
+ // If the importer is in node compatibility mode or this is not an ESM
22
+ // file that has been converted to a CommonJS file using a Babel-
23
+ // compatible transform (i.e. "__esModule" has not been set), then set
24
+ // "default" to the CommonJS "module.exports" for node compatibility.
25
+ isNodeMode || !mod || !mod.__esModule ? __defProp(target, "default", { value: mod, enumerable: true }) : target,
26
+ mod
27
+ ));
18
28
  var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod);
19
29
 
20
30
  // source/index.ts
21
31
  var index_exports = {};
22
32
  __export(index_exports, {
23
33
  MemoryStore: () => MemoryStore,
24
- default: () => lib_default,
25
- rateLimit: () => lib_default
34
+ default: () => rate_limit_default,
35
+ ipKeyGenerator: () => ipKeyGenerator,
36
+ rateLimit: () => rate_limit_default
26
37
  });
27
38
  module.exports = __toCommonJS(index_exports);
28
39
 
40
+ // source/ip-key-generator.ts
41
+ var import_node_net = require("node:net");
42
+ var import_ip = __toESM(require("ip"), 1);
43
+ function ipKeyGenerator(ip, ipv6Subnet = 56) {
44
+ if (ipv6Subnet && (0, import_node_net.isIPv6)(ip)) {
45
+ return `${import_ip.default.mask(
46
+ ip,
47
+ import_ip.default.fromPrefixLen(ipv6Subnet)
48
+ )}/${ipv6Subnet}`;
49
+ }
50
+ return ip;
51
+ }
52
+
53
+ // source/memory-store.ts
54
+ var MemoryStore = class {
55
+ constructor() {
56
+ /**
57
+ * These two maps store usage (requests) and reset time by key (for example, IP
58
+ * addresses or API keys).
59
+ *
60
+ * They are split into two to avoid having to iterate through the entire set to
61
+ * determine which ones need reset. Instead, `Client`s are moved from `previous`
62
+ * to `current` as they hit the endpoint. Once `windowMs` has elapsed, all clients
63
+ * left in `previous`, i.e., those that have not made any recent requests, are
64
+ * known to be expired and can be deleted in bulk.
65
+ */
66
+ this.previous = /* @__PURE__ */ new Map();
67
+ this.current = /* @__PURE__ */ new Map();
68
+ /**
69
+ * Confirmation that the keys incremented in once instance of MemoryStore
70
+ * cannot affect other instances.
71
+ */
72
+ this.localKeys = true;
73
+ }
74
+ /**
75
+ * Method that initializes the store.
76
+ *
77
+ * @param options {Options} - The options used to setup the middleware.
78
+ */
79
+ init(options) {
80
+ this.windowMs = options.windowMs;
81
+ if (this.interval) clearInterval(this.interval);
82
+ this.interval = setInterval(() => {
83
+ this.clearExpired();
84
+ }, this.windowMs);
85
+ this.interval.unref?.();
86
+ }
87
+ /**
88
+ * Method to fetch a client's hit count and reset time.
89
+ *
90
+ * @param key {string} - The identifier for a client.
91
+ *
92
+ * @returns {ClientRateLimitInfo | undefined} - The number of hits and reset time for that client.
93
+ *
94
+ * @public
95
+ */
96
+ async get(key) {
97
+ return this.current.get(key) ?? this.previous.get(key);
98
+ }
99
+ /**
100
+ * Method to increment a client's hit counter.
101
+ *
102
+ * @param key {string} - The identifier for a client.
103
+ *
104
+ * @returns {ClientRateLimitInfo} - The number of hits and reset time for that client.
105
+ *
106
+ * @public
107
+ */
108
+ async increment(key) {
109
+ const client = this.getClient(key);
110
+ const now = Date.now();
111
+ if (client.resetTime.getTime() <= now) {
112
+ this.resetClient(client, now);
113
+ }
114
+ client.totalHits++;
115
+ return client;
116
+ }
117
+ /**
118
+ * Method to decrement a client's hit counter.
119
+ *
120
+ * @param key {string} - The identifier for a client.
121
+ *
122
+ * @public
123
+ */
124
+ async decrement(key) {
125
+ const client = this.getClient(key);
126
+ if (client.totalHits > 0) client.totalHits--;
127
+ }
128
+ /**
129
+ * Method to reset a client's hit counter.
130
+ *
131
+ * @param key {string} - The identifier for a client.
132
+ *
133
+ * @public
134
+ */
135
+ async resetKey(key) {
136
+ this.current.delete(key);
137
+ this.previous.delete(key);
138
+ }
139
+ /**
140
+ * Method to reset everyone's hit counter.
141
+ *
142
+ * @public
143
+ */
144
+ async resetAll() {
145
+ this.current.clear();
146
+ this.previous.clear();
147
+ }
148
+ /**
149
+ * Method to stop the timer (if currently running) and prevent any memory
150
+ * leaks.
151
+ *
152
+ * @public
153
+ */
154
+ shutdown() {
155
+ clearInterval(this.interval);
156
+ void this.resetAll();
157
+ }
158
+ /**
159
+ * Recycles a client by setting its hit count to zero, and reset time to
160
+ * `windowMs` milliseconds from now.
161
+ *
162
+ * NOT to be confused with `#resetKey()`, which removes a client from both the
163
+ * `current` and `previous` maps.
164
+ *
165
+ * @param client {Client} - The client to recycle.
166
+ * @param now {number} - The current time, to which the `windowMs` is added to get the `resetTime` for the client.
167
+ *
168
+ * @return {Client} - The modified client that was passed in, to allow for chaining.
169
+ */
170
+ resetClient(client, now = Date.now()) {
171
+ client.totalHits = 0;
172
+ client.resetTime.setTime(now + this.windowMs);
173
+ return client;
174
+ }
175
+ /**
176
+ * Retrieves or creates a client, given a key. Also ensures that the client being
177
+ * returned is in the `current` map.
178
+ *
179
+ * @param key {string} - The key under which the client is (or is to be) stored.
180
+ *
181
+ * @returns {Client} - The requested client.
182
+ */
183
+ getClient(key) {
184
+ if (this.current.has(key)) return this.current.get(key);
185
+ let client;
186
+ if (this.previous.has(key)) {
187
+ client = this.previous.get(key);
188
+ this.previous.delete(key);
189
+ } else {
190
+ client = { totalHits: 0, resetTime: /* @__PURE__ */ new Date() };
191
+ this.resetClient(client);
192
+ }
193
+ this.current.set(key, client);
194
+ return client;
195
+ }
196
+ /**
197
+ * Move current clients to previous, create a new map for current.
198
+ *
199
+ * This function is called every `windowMs`.
200
+ */
201
+ clearExpired() {
202
+ this.previous = this.current;
203
+ this.current = /* @__PURE__ */ new Map();
204
+ }
205
+ };
206
+
207
+ // source/rate-limit.ts
208
+ var import_node_net3 = require("node:net");
209
+
29
210
  // source/headers.ts
30
211
  var import_node_buffer = require("node:buffer");
31
212
  var import_node_crypto = require("node:crypto");
@@ -34,12 +215,12 @@ var SUPPORTED_DRAFT_VERSIONS = [
34
215
  "draft-7",
35
216
  "draft-8"
36
217
  ];
37
- var getResetSeconds = (resetTime, windowMs) => {
38
- let resetSeconds = void 0;
218
+ var getResetSeconds = (windowMs, resetTime) => {
219
+ let resetSeconds;
39
220
  if (resetTime) {
40
221
  const deltaSeconds = Math.ceil((resetTime.getTime() - Date.now()) / 1e3);
41
222
  resetSeconds = Math.max(0, deltaSeconds);
42
- } else if (windowMs) {
223
+ } else {
43
224
  resetSeconds = Math.ceil(windowMs / 1e3);
44
225
  }
45
226
  return resetSeconds;
@@ -65,7 +246,7 @@ var setLegacyHeaders = (response, info) => {
65
246
  var setDraft6Headers = (response, info, windowMs) => {
66
247
  if (response.headersSent) return;
67
248
  const windowSeconds = Math.ceil(windowMs / 1e3);
68
- const resetSeconds = getResetSeconds(info.resetTime);
249
+ const resetSeconds = getResetSeconds(windowMs, info.resetTime);
69
250
  response.setHeader("RateLimit-Policy", `${info.limit};w=${windowSeconds}`);
70
251
  response.setHeader("RateLimit-Limit", info.limit.toString());
71
252
  response.setHeader("RateLimit-Remaining", info.remaining.toString());
@@ -75,7 +256,7 @@ var setDraft6Headers = (response, info, windowMs) => {
75
256
  var setDraft7Headers = (response, info, windowMs) => {
76
257
  if (response.headersSent) return;
77
258
  const windowSeconds = Math.ceil(windowMs / 1e3);
78
- const resetSeconds = getResetSeconds(info.resetTime, windowMs);
259
+ const resetSeconds = getResetSeconds(windowMs, info.resetTime);
79
260
  response.setHeader("RateLimit-Policy", `${info.limit};w=${windowSeconds}`);
80
261
  response.setHeader(
81
262
  "RateLimit",
@@ -85,21 +266,33 @@ var setDraft7Headers = (response, info, windowMs) => {
85
266
  var setDraft8Headers = (response, info, windowMs, name, key) => {
86
267
  if (response.headersSent) return;
87
268
  const windowSeconds = Math.ceil(windowMs / 1e3);
88
- const resetSeconds = getResetSeconds(info.resetTime, windowMs);
269
+ const resetSeconds = getResetSeconds(windowMs, info.resetTime);
89
270
  const partitionKey = getPartitionKey(key);
90
- const policy = `q=${info.limit}; w=${windowSeconds}; pk=:${partitionKey}:`;
91
271
  const header = `r=${info.remaining}; t=${resetSeconds}`;
92
- response.append("RateLimit-Policy", `"${name}"; ${policy}`);
272
+ const policy = `q=${info.limit}; w=${windowSeconds}; pk=:${partitionKey}:`;
93
273
  response.append("RateLimit", `"${name}"; ${header}`);
274
+ response.append("RateLimit-Policy", `"${name}"; ${policy}`);
94
275
  };
95
276
  var setRetryAfterHeader = (response, info, windowMs) => {
96
277
  if (response.headersSent) return;
97
- const resetSeconds = getResetSeconds(info.resetTime, windowMs);
278
+ const resetSeconds = getResetSeconds(windowMs, info.resetTime);
98
279
  response.setHeader("Retry-After", resetSeconds.toString());
99
280
  };
100
281
 
282
+ // source/utils.ts
283
+ var omitUndefinedProperties = (passedOptions) => {
284
+ const omittedOptions = {};
285
+ for (const k of Object.keys(passedOptions)) {
286
+ const key = k;
287
+ if (passedOptions[key] !== void 0) {
288
+ omittedOptions[key] = passedOptions[key];
289
+ }
290
+ }
291
+ return omittedOptions;
292
+ };
293
+
101
294
  // source/validations.ts
102
- var import_node_net = require("node:net");
295
+ var import_node_net2 = require("node:net");
103
296
  var ValidationError = class extends Error {
104
297
  /**
105
298
  * The code must be a string, in snake case and all capital, that starts with
@@ -121,7 +314,6 @@ var ChangeWarning = class extends ValidationError {
121
314
  var usedStores = /* @__PURE__ */ new Set();
122
315
  var singleCountKeys = /* @__PURE__ */ new WeakMap();
123
316
  var validations = {
124
- // eslint-disable-next-line @typescript-eslint/consistent-type-assertions
125
317
  enabled: {
126
318
  default: true
127
319
  },
@@ -146,7 +338,7 @@ var validations = {
146
338
  `An undefined 'request.ip' was detected. This might indicate a misconfiguration or the connection being destroyed prematurely.`
147
339
  );
148
340
  }
149
- if (!(0, import_node_net.isIP)(ip)) {
341
+ if (!(0, import_node_net2.isIP)(ip)) {
150
342
  throw new ValidationError(
151
343
  "ERR_ERL_INVALID_IP_ADDRESS",
152
344
  `An invalid 'request.ip' (${ip}) was detected. Consider passing a custom 'keyGenerator' function to the rate limiter.`
@@ -357,7 +549,8 @@ var validations = {
357
549
  const { stack } = new Error(
358
550
  "express-rate-limit validation check (set options.validate.creationStack=false to disable)"
359
551
  );
360
- if (stack?.includes("Layer.handle [as handle_request]")) {
552
+ if (stack?.includes("Layer.handle [as handle_request]") || // express v4
553
+ stack?.includes("Layer.handleRequest")) {
361
554
  if (!store.localKeys) {
362
555
  throw new ValidationError(
363
556
  "ERR_ERL_CREATED_IN_REQUEST_HANDLER",
@@ -369,6 +562,37 @@ var validations = {
369
562
  `express-rate-limit instance should be created at app initialization, not when responding to a request.`
370
563
  );
371
564
  }
565
+ },
566
+ ipv6Subnet(ipv6Subnet) {
567
+ if (ipv6Subnet === false) {
568
+ return;
569
+ }
570
+ if (!Number.isInteger(ipv6Subnet) || ipv6Subnet < 32 || ipv6Subnet > 64) {
571
+ throw new ValidationError(
572
+ "ERR_ERL_IPV6_SUBNET",
573
+ `Unexpected ipv6Subnet value: ${ipv6Subnet}. Expected an integer between 32 and 64 (usually 48-64).`
574
+ );
575
+ }
576
+ },
577
+ ipv6SubnetOrKeyGenerator(options) {
578
+ if (options.ipv6Subnet !== void 0 && options.keyGenerator) {
579
+ throw new ValidationError(
580
+ "ERR_ERL_IPV6SUBNET_OR_KEYGENERATOR",
581
+ `Incompatible options: the 'ipv6Subnet' option is ignored when a custom 'keyGenerator' function is also set.`
582
+ );
583
+ }
584
+ },
585
+ keyGeneratorIpFallback(keyGenerator) {
586
+ if (!keyGenerator) {
587
+ return;
588
+ }
589
+ const src = keyGenerator.toString();
590
+ if ((src.includes("req.ip") || src.includes("request.ip")) && !src.includes("ipKeyGenerator")) {
591
+ throw new ValidationError(
592
+ "ERR_ERL_KEY_GEN_IPV6",
593
+ `Custom keyGenerator appears to use request IP without calling the ipKeyGenerator helper function for IPv6 addresses. This could allow IPv6 users to bypass limits.`
594
+ );
595
+ }
372
596
  }
373
597
  };
374
598
  var getValidations = (_enabled) => {
@@ -383,9 +607,7 @@ var getValidations = (_enabled) => {
383
607
  ..._enabled
384
608
  };
385
609
  }
386
- const wrappedValidations = {
387
- enabled
388
- };
610
+ const wrappedValidations = { enabled };
389
611
  for (const [name, validation] of Object.entries(validations)) {
390
612
  if (typeof validation === "function")
391
613
  wrappedValidations[name] = (...args) => {
@@ -407,161 +629,7 @@ var getValidations = (_enabled) => {
407
629
  return wrappedValidations;
408
630
  };
409
631
 
410
- // source/memory-store.ts
411
- var MemoryStore = class {
412
- constructor() {
413
- /**
414
- * These two maps store usage (requests) and reset time by key (for example, IP
415
- * addresses or API keys).
416
- *
417
- * They are split into two to avoid having to iterate through the entire set to
418
- * determine which ones need reset. Instead, `Client`s are moved from `previous`
419
- * to `current` as they hit the endpoint. Once `windowMs` has elapsed, all clients
420
- * left in `previous`, i.e., those that have not made any recent requests, are
421
- * known to be expired and can be deleted in bulk.
422
- */
423
- this.previous = /* @__PURE__ */ new Map();
424
- this.current = /* @__PURE__ */ new Map();
425
- /**
426
- * Confirmation that the keys incremented in once instance of MemoryStore
427
- * cannot affect other instances.
428
- */
429
- this.localKeys = true;
430
- }
431
- /**
432
- * Method that initializes the store.
433
- *
434
- * @param options {Options} - The options used to setup the middleware.
435
- */
436
- init(options) {
437
- this.windowMs = options.windowMs;
438
- if (this.interval) clearInterval(this.interval);
439
- this.interval = setInterval(() => {
440
- this.clearExpired();
441
- }, this.windowMs);
442
- if (this.interval.unref) this.interval.unref();
443
- }
444
- /**
445
- * Method to fetch a client's hit count and reset time.
446
- *
447
- * @param key {string} - The identifier for a client.
448
- *
449
- * @returns {ClientRateLimitInfo | undefined} - The number of hits and reset time for that client.
450
- *
451
- * @public
452
- */
453
- async get(key) {
454
- return this.current.get(key) ?? this.previous.get(key);
455
- }
456
- /**
457
- * Method to increment a client's hit counter.
458
- *
459
- * @param key {string} - The identifier for a client.
460
- *
461
- * @returns {ClientRateLimitInfo} - The number of hits and reset time for that client.
462
- *
463
- * @public
464
- */
465
- async increment(key) {
466
- const client = this.getClient(key);
467
- const now = Date.now();
468
- if (client.resetTime.getTime() <= now) {
469
- this.resetClient(client, now);
470
- }
471
- client.totalHits++;
472
- return client;
473
- }
474
- /**
475
- * Method to decrement a client's hit counter.
476
- *
477
- * @param key {string} - The identifier for a client.
478
- *
479
- * @public
480
- */
481
- async decrement(key) {
482
- const client = this.getClient(key);
483
- if (client.totalHits > 0) client.totalHits--;
484
- }
485
- /**
486
- * Method to reset a client's hit counter.
487
- *
488
- * @param key {string} - The identifier for a client.
489
- *
490
- * @public
491
- */
492
- async resetKey(key) {
493
- this.current.delete(key);
494
- this.previous.delete(key);
495
- }
496
- /**
497
- * Method to reset everyone's hit counter.
498
- *
499
- * @public
500
- */
501
- async resetAll() {
502
- this.current.clear();
503
- this.previous.clear();
504
- }
505
- /**
506
- * Method to stop the timer (if currently running) and prevent any memory
507
- * leaks.
508
- *
509
- * @public
510
- */
511
- shutdown() {
512
- clearInterval(this.interval);
513
- void this.resetAll();
514
- }
515
- /**
516
- * Recycles a client by setting its hit count to zero, and reset time to
517
- * `windowMs` milliseconds from now.
518
- *
519
- * NOT to be confused with `#resetKey()`, which removes a client from both the
520
- * `current` and `previous` maps.
521
- *
522
- * @param client {Client} - The client to recycle.
523
- * @param now {number} - The current time, to which the `windowMs` is added to get the `resetTime` for the client.
524
- *
525
- * @return {Client} - The modified client that was passed in, to allow for chaining.
526
- */
527
- resetClient(client, now = Date.now()) {
528
- client.totalHits = 0;
529
- client.resetTime.setTime(now + this.windowMs);
530
- return client;
531
- }
532
- /**
533
- * Retrieves or creates a client, given a key. Also ensures that the client being
534
- * returned is in the `current` map.
535
- *
536
- * @param key {string} - The key under which the client is (or is to be) stored.
537
- *
538
- * @returns {Client} - The requested client.
539
- */
540
- getClient(key) {
541
- if (this.current.has(key)) return this.current.get(key);
542
- let client;
543
- if (this.previous.has(key)) {
544
- client = this.previous.get(key);
545
- this.previous.delete(key);
546
- } else {
547
- client = { totalHits: 0, resetTime: /* @__PURE__ */ new Date() };
548
- this.resetClient(client);
549
- }
550
- this.current.set(key, client);
551
- return client;
552
- }
553
- /**
554
- * Move current clients to previous, create a new map for current.
555
- *
556
- * This function is called every `windowMs`.
557
- */
558
- clearExpired() {
559
- this.previous = this.current;
560
- this.current = /* @__PURE__ */ new Map();
561
- }
562
- };
563
-
564
- // source/lib.ts
632
+ // source/rate-limit.ts
565
633
  var isLegacyStore = (store) => (
566
634
  // Check that `incr` exists but `increment` does not - store authors might want
567
635
  // to keep both around for backwards compatibility.
@@ -605,18 +673,8 @@ var getOptionsFromConfig = (config) => {
605
673
  validate: validations2.enabled
606
674
  };
607
675
  };
608
- var omitUndefinedOptions = (passedOptions) => {
609
- const omittedOptions = {};
610
- for (const k of Object.keys(passedOptions)) {
611
- const key = k;
612
- if (passedOptions[key] !== void 0) {
613
- omittedOptions[key] = passedOptions[key];
614
- }
615
- }
616
- return omittedOptions;
617
- };
618
676
  var parseOptions = (passedOptions) => {
619
- const notUndefinedOptions = omitUndefinedOptions(passedOptions);
677
+ const notUndefinedOptions = omitUndefinedProperties(passedOptions);
620
678
  const validations2 = getValidations(notUndefinedOptions?.validate ?? true);
621
679
  validations2.validationsConfig();
622
680
  validations2.draftPolliHeaders(
@@ -624,6 +682,11 @@ var parseOptions = (passedOptions) => {
624
682
  notUndefinedOptions.draft_polli_ratelimit_headers
625
683
  );
626
684
  validations2.onLimitReached(notUndefinedOptions.onLimitReached);
685
+ if (notUndefinedOptions.ipv6Subnet !== void 0 && typeof notUndefinedOptions.ipv6Subnet !== "function") {
686
+ validations2.ipv6Subnet(notUndefinedOptions.ipv6Subnet);
687
+ }
688
+ validations2.keyGeneratorIpFallback(notUndefinedOptions.keyGenerator);
689
+ validations2.ipv6SubnetOrKeyGenerator(notUndefinedOptions);
627
690
  let standardHeaders = notUndefinedOptions.standardHeaders ?? false;
628
691
  if (standardHeaders === true) standardHeaders = "draft-6";
629
692
  const config = {
@@ -652,21 +715,27 @@ var parseOptions = (passedOptions) => {
652
715
  skipSuccessfulRequests: false,
653
716
  requestWasSuccessful: (_request, response) => response.statusCode < 400,
654
717
  skip: (_request, _response) => false,
655
- keyGenerator(request, _response) {
718
+ async keyGenerator(request, response) {
656
719
  validations2.ip(request.ip);
657
720
  validations2.trustProxy(request);
658
721
  validations2.xForwardedForHeader(request);
659
- return request.ip;
722
+ const ip = request.ip;
723
+ let subnet = 56;
724
+ if ((0, import_node_net3.isIPv6)(ip)) {
725
+ subnet = typeof config.ipv6Subnet === "function" ? await config.ipv6Subnet(request, response) : config.ipv6Subnet;
726
+ if (typeof config.ipv6Subnet === "function")
727
+ validations2.ipv6Subnet(subnet);
728
+ }
729
+ return ipKeyGenerator(ip, subnet);
660
730
  },
731
+ ipv6Subnet: 56,
661
732
  async handler(request, response, _next, _optionsUsed) {
662
733
  response.status(config.statusCode);
663
734
  const message = typeof config.message === "function" ? await config.message(
664
735
  request,
665
736
  response
666
737
  ) : config.message;
667
- if (!response.writableEnded) {
668
- response.send(message);
669
- }
738
+ if (!response.writableEnded) response.send(message);
670
739
  },
671
740
  passOnStoreError: false,
672
741
  // Allow the default options to be overridden by the passed options.
@@ -734,7 +803,8 @@ var rateLimit = (passedOptions) => {
734
803
  limit,
735
804
  used: totalHits,
736
805
  remaining: Math.max(limit - totalHits, 0),
737
- resetTime
806
+ resetTime,
807
+ key
738
808
  };
739
809
  Object.defineProperty(info, "current", {
740
810
  configurable: false,
@@ -814,10 +884,11 @@ var rateLimit = (passedOptions) => {
814
884
  middleware.getKey = typeof config.store.get === "function" ? config.store.get.bind(config.store) : getThrowFn;
815
885
  return middleware;
816
886
  };
817
- var lib_default = rateLimit;
887
+ var rate_limit_default = rateLimit;
818
888
  // Annotate the CommonJS export names for ESM import in node:
819
889
  0 && (module.exports = {
820
890
  MemoryStore,
891
+ ipKeyGenerator,
821
892
  rateLimit
822
893
  });
823
894
  module.exports = rateLimit; module.exports.default = rateLimit; module.exports.rateLimit = rateLimit; module.exports.MemoryStore = MemoryStore;