express-rate-limiter-ts
Version:
A powerful, flexible and modern rate limiter middleware for Express.js written in TypeScript.
107 lines (106 loc) • 3.96 kB
JavaScript
"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
exports.MongoStore = void 0;
const mongodb_1 = require("mongodb");
// MongoStore: Production için tam çalışan, asenkron, TTL ve ban destekli bir store.
class MongoStore {
constructor(options) {
this.windowMs = options.windowMs;
this.client = new mongodb_1.MongoClient(options.uri);
}
// Start connection (should be called on first use)
async connect() {
if (!this.db) {
await this.client.connect();
this.db = this.client.db();
this.counters = this.db.collection('rateLimiter_counters');
this.bans = this.db.collection('rateLimiter_bans');
this.stats = this.db.collection('rateLimiter_stats');
// Create TTL indexes (one time only)
await this.counters.createIndex({ expiresAt: 1 }, { expireAfterSeconds: 0 });
await this.bans.createIndex({ expiresAt: 1 }, { expireAfterSeconds: 0 });
}
}
// Increment counter and check limit
async incr(key) {
var _a, _b;
await this.connect();
const now = new Date();
const expiresAt = new Date(now.getTime() + this.windowMs);
const result = await this.counters.findOneAndUpdate({ key }, {
$inc: { count: 1 },
$setOnInsert: { createdAt: now },
$set: { expiresAt },
}, { upsert: true, returnDocument: 'after' });
return {
current: (_b = (_a = result === null || result === void 0 ? void 0 : result.value) === null || _a === void 0 ? void 0 : _a.count) !== null && _b !== void 0 ? _b : 1,
remaining: 0, // Remaining limit will be calculated in middleware
resetTime: expiresAt,
exceeded: false,
};
}
// Read counter
async get(key) {
await this.connect();
const doc = await this.counters.findOne({ key });
if (!doc)
return { count: 0, resetTime: Date.now() + this.windowMs };
return { count: doc.count, resetTime: doc.expiresAt.getTime() };
}
// Reset counter
async reset(key) {
await this.connect();
await this.counters.deleteOne({ key });
}
// Record statistics
async recordStat(route) {
await this.connect();
await this.stats.updateOne({ route }, { $inc: { count: 1 }, $set: { lastTriggered: new Date() } }, { upsert: true });
}
// Get statistics
async getStats() {
await this.connect();
const docs = await this.stats.find().toArray();
const stats = {};
for (const doc of docs) {
stats[doc.route] = {
count: doc.count,
lastTriggered: doc.lastTriggered,
};
}
return stats;
}
// Apply ban
async ban(key, seconds, reason) {
await this.connect();
const expiresAt = new Date(Date.now() + seconds * 1000);
await this.bans.updateOne({ key }, { $set: { reason, expiresAt } }, { upsert: true });
}
// Check ban
async isBanned(key) {
await this.connect();
const doc = await this.bans.findOne({ key });
if (doc && doc.expiresAt > new Date()) {
return { banned: true, banExpiresAt: doc.expiresAt, reason: doc.reason };
}
return { banned: false };
}
// Get banned keys
async getBanned() {
await this.connect();
const now = new Date();
const docs = await this.bans.find({ expiresAt: { $gt: now } }).toArray();
const result = {};
for (const doc of docs) {
result[doc.key] = { banExpiresAt: doc.expiresAt, reason: doc.reason };
}
return result;
}
// Remove ban
async unban(key) {
await this.connect();
await this.bans.deleteOne({ key });
await this.counters.deleteOne({ key });
}
}
exports.MongoStore = MongoStore;