var __defProp = Object.defineProperty; var __getOwnPropDesc = Object.getOwnPropertyDescriptor; var __getOwnPropNames = Object.getOwnPropertyNames; var __hasOwnProp = Object.prototype.hasOwnProperty; var __markAsModule = (target) => __defProp(target, "__esModule", { value: true }); var __export = (target, all) => { for (var name in all) __defProp(target, name, { get: all[name], enumerable: true }); }; var __reExport = (target, module2, copyDefault, desc) => { if (module2 && typeof module2 === "object" || typeof module2 === "function") { for (let key of __getOwnPropNames(module2)) if (!__hasOwnProp.call(target, key) && (copyDefault || key !== "default")) __defProp(target, key, { get: () => module2[key], enumerable: !(desc = __getOwnPropDesc(module2, key)) || desc.enumerable }); } return target; }; var __toCommonJS = /* @__PURE__ */ ((cache) => { return (module2, temp) => { return cache && cache.get(module2) || (temp = __reExport(__markAsModule({}), module2, 1), cache && cache.set(module2, temp), temp); }; })(typeof WeakMap !== "undefined" ? /* @__PURE__ */ new WeakMap() : 0); // source/index.ts var source_exports = {}; __export(source_exports, { default: () => lib_default, rateLimit: () => lib_default }); // source/memory-store.ts var calculateNextResetTime = (windowMs) => { const resetTime = new Date(); resetTime.setMilliseconds(resetTime.getMilliseconds() + windowMs); return resetTime; }; var MemoryStore = class { init(options) { this.windowMs = options.windowMs; this.resetTime = calculateNextResetTime(this.windowMs); this.hits = {}; const interval = setInterval(async () => { await this.resetAll(); }, this.windowMs); if (interval.unref) { interval.unref(); } } async increment(key) { const totalHits = (this.hits[key] ?? 0) + 1; this.hits[key] = totalHits; return { totalHits, resetTime: this.resetTime }; } async decrement(key) { const current = this.hits[key]; if (current) { this.hits[key] = current - 1; } } async resetKey(key) { delete this.hits[key]; } async resetAll() { this.hits = {}; this.resetTime = calculateNextResetTime(this.windowMs); } }; // source/lib.ts var isLegacyStore = (store) => typeof store.incr === "function" && typeof store.increment !== "function"; var promisifyStore = (passedStore) => { if (!isLegacyStore(passedStore)) { return passedStore; } const legacyStore = passedStore; class PromisifiedStore { async increment(key) { return new Promise((resolve, reject) => { legacyStore.incr(key, (error, totalHits, resetTime) => { if (error) reject(error); resolve({ totalHits, resetTime }); }); }); } async decrement(key) { return Promise.resolve(legacyStore.decrement(key)); } async resetKey(key) { return Promise.resolve(legacyStore.resetKey(key)); } async resetAll() { if (typeof legacyStore.resetAll === "function") return Promise.resolve(legacyStore.resetAll()); } } return new PromisifiedStore(); }; var parseOptions = (passedOptions) => { const options = { windowMs: 60 * 1e3, store: new MemoryStore(), max: 5, message: "Too many requests, please try again later.", statusCode: 429, legacyHeaders: passedOptions.headers ?? true, standardHeaders: passedOptions.draft_polli_ratelimit_headers ?? false, requestPropertyName: "rateLimit", skipFailedRequests: false, skipSuccessfulRequests: false, requestWasSuccessful: (_request, response) => response.statusCode < 400, skip: (_request, _response) => false, keyGenerator: (request, _response) => { if (!request.ip) { console.error("WARN | `express-rate-limit` | `request.ip` is undefined. You can avoid this by providing a custom `keyGenerator` function, but it may be indicative of a larger issue."); } return request.ip; }, handler: (_request, response, _next, _optionsUsed) => { response.status(options.statusCode).send(options.message); }, onLimitReached: (_request, _response, _optionsUsed) => { }, ...passedOptions }; if (typeof options.store.incr !== "function" && typeof options.store.increment !== "function" || typeof options.store.decrement !== "function" || typeof options.store.resetKey !== "function" || typeof options.store.resetAll !== "undefined" && typeof options.store.resetAll !== "function" || typeof options.store.init !== "undefined" && typeof options.store.init !== "function") { throw new TypeError("An invalid store was passed. Please ensure that the store is a class that implements the `Store` interface."); } options.store = promisifyStore(options.store); return options; }; var handleAsyncErrors = (fn) => async (request, response, next) => { try { await Promise.resolve(fn(request, response, next)).catch(next); } catch (error) { next(error); } }; var rateLimit = (passedOptions) => { const options = parseOptions(passedOptions ?? {}); if (typeof options.store.init === "function") options.store.init(options); const middleware = handleAsyncErrors(async (request, response, next) => { const skip = await options.skip(request, response); if (skip) { next(); return; } const augmentedRequest = request; const key = await options.keyGenerator(request, response); const { totalHits, resetTime } = await options.store.increment(key); const retrieveQuota = typeof options.max === "function" ? options.max(request, response) : options.max; const maxHits = await retrieveQuota; augmentedRequest[options.requestPropertyName] = { limit: maxHits, current: totalHits, remaining: Math.max(maxHits - totalHits, 0), resetTime }; if (options.legacyHeaders && !response.headersSent) { response.setHeader("X-RateLimit-Limit", maxHits); response.setHeader("X-RateLimit-Remaining", augmentedRequest[options.requestPropertyName].remaining); if (resetTime instanceof Date) { response.setHeader("Date", new Date().toUTCString()); response.setHeader("X-RateLimit-Reset", Math.ceil(resetTime.getTime() / 1e3)); } } if (options.standardHeaders && !response.headersSent) { response.setHeader("RateLimit-Limit", maxHits); response.setHeader("RateLimit-Remaining", augmentedRequest[options.requestPropertyName].remaining); if (resetTime) { const deltaSeconds = Math.ceil((resetTime.getTime() - Date.now()) / 1e3); response.setHeader("RateLimit-Reset", Math.max(0, deltaSeconds)); } } if (options.skipFailedRequests || options.skipSuccessfulRequests) { let decremented = false; const decrementKey = async () => { if (!decremented) { await options.store.decrement(key); decremented = true; } }; if (options.skipFailedRequests) { response.on("finish", async () => { if (!options.requestWasSuccessful(request, response)) await decrementKey(); }); response.on("close", async () => { if (!response.writableEnded) await decrementKey(); }); response.on("error", async () => { await decrementKey(); }); } if (options.skipSuccessfulRequests) { response.on("finish", async () => { if (options.requestWasSuccessful(request, response)) await decrementKey(); }); } } if (maxHits && totalHits === maxHits + 1) { options.onLimitReached(request, response, options); } if (maxHits && totalHits > maxHits) { if ((options.legacyHeaders || options.standardHeaders) && !response.headersSent) { response.setHeader("Retry-After", Math.ceil(options.windowMs / 1e3)); } options.handler(request, response, next, options); return; } next(); }); middleware.resetKey = options.store.resetKey.bind(options.store); return middleware; }; var lib_default = rateLimit; module.exports = __toCommonJS(source_exports); module.exports = rateLimit; module.exports.default = rateLimit; module.exports.rateLimit = rateLimit;