express-rate-limiter-ts
Version:
A powerful, flexible and modern rate limiter middleware for Express.js written in TypeScript.
136 lines (135 loc) • 5.63 kB
JavaScript
"use strict";
var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) {
function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); }
return new (P || (P = Promise))(function (resolve, reject) {
function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } }
function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } }
function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); }
step((generator = generator.apply(thisArg, _arguments || [])).next());
});
};
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);
}
// Bağlantıyı başlat (ilk kullanımda çağrılmalı)
connect() {
return __awaiter(this, void 0, void 0, function* () {
if (!this.db) {
yield 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');
// TTL index'leri oluştur (bir kereye mahsus)
yield this.counters.createIndex({ expiresAt: 1 }, { expireAfterSeconds: 0 });
yield this.bans.createIndex({ expiresAt: 1 }, { expireAfterSeconds: 0 });
}
});
}
// Sayaç artırma ve limiti kontrol etme
incr(key) {
return __awaiter(this, void 0, void 0, function* () {
var _a, _b;
yield this.connect();
const now = new Date();
const expiresAt = new Date(now.getTime() + this.windowMs);
const result = yield 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, // Kalan limit middleware'de hesaplanacak
resetTime: expiresAt,
exceeded: false,
};
});
}
// Sayaç okuma
get(key) {
return __awaiter(this, void 0, void 0, function* () {
yield this.connect();
const doc = yield this.counters.findOne({ key });
if (!doc)
return { count: 0, resetTime: Date.now() + this.windowMs };
return { count: doc.count, resetTime: doc.expiresAt.getTime() };
});
}
// Sayaç sıfırlama
reset(key) {
return __awaiter(this, void 0, void 0, function* () {
yield this.connect();
yield this.counters.deleteOne({ key });
});
}
// İstatistik kaydı
recordStat(route) {
return __awaiter(this, void 0, void 0, function* () {
yield this.connect();
yield this.stats.updateOne({ route }, { $inc: { count: 1 }, $set: { lastTriggered: new Date() } }, { upsert: true });
});
}
// İstatistikleri döndür
getStats() {
return __awaiter(this, void 0, void 0, function* () {
yield this.connect();
const docs = yield this.stats.find().toArray();
const stats = {};
for (const doc of docs) {
stats[doc.route] = {
count: doc.count,
lastTriggered: doc.lastTriggered,
};
}
return stats;
});
}
// Ban uygula
ban(key, seconds, reason) {
return __awaiter(this, void 0, void 0, function* () {
yield this.connect();
const expiresAt = new Date(Date.now() + seconds * 1000);
yield this.bans.updateOne({ key }, { $set: { reason, expiresAt } }, { upsert: true });
});
}
// Ban kontrolü
isBanned(key) {
return __awaiter(this, void 0, void 0, function* () {
yield this.connect();
const doc = yield this.bans.findOne({ key });
if (doc && doc.expiresAt > new Date()) {
return { banned: true, banExpiresAt: doc.expiresAt, reason: doc.reason };
}
return { banned: false };
});
}
// Banlı anahtarları döndür
getBanned() {
return __awaiter(this, void 0, void 0, function* () {
yield this.connect();
const now = new Date();
const docs = yield 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;
});
}
// Ban kaldır
unban(key) {
return __awaiter(this, void 0, void 0, function* () {
yield this.connect();
yield this.bans.deleteOne({ key });
yield this.counters.deleteOne({ key });
});
}
}
exports.MongoStore = MongoStore;