UNPKG

express-rate-limit-ioredis-store

Version:

A redis store implementation to be used alongside ioredis for the express-rate-limit middleware

63 lines (53 loc) 1.82 kB
import {IncrementResponse, Options, Store} from 'express-rate-limit'; import Redis from 'ioredis'; type RedisStoreOptions = { globalPrefix?: string; client: Redis.Redis; }; export default class ExpressRateLimitIORedisStore implements Store { private client: Redis.Redis; private globalPrefix: string; private windowMs: number; constructor({globalPrefix, client}: RedisStoreOptions) { this.client = client; this.globalPrefix = globalPrefix ?? 'express-rate-limit-store-'; this.windowMs = 0; } init(options: Options): void { this.windowMs = options.windowMs; } async increment(key: string): Promise<IncrementResponse> { const redisKey = this.getFullKey(key); const totalHits = await this.client.incr(redisKey); const insertionTime = await this.getInsertionTime(redisKey, totalHits); const expiryTime = insertionTime + this.windowMs; await this.client.pexpireat(redisKey, expiryTime); return { totalHits, resetTime: new Date(expiryTime), }; } async decrement(key: string): Promise<void> { const redisKey = this.getFullKey(key); if (await this.client.get(redisKey)) { await this.client.decr(redisKey); } } async resetKey(key: string): Promise<void> { await this.client.del(this.getFullKey(key)); } private getFullKey(key: string) { return this.globalPrefix + key; } private async getInsertionTime(key: string, value: number) { const isKeyInsertion = value === 1; if (isKeyInsertion) { const now = new Date().getTime(); await this.client.set(key + '-create-time', now); await this.client.pexpire(key + '-create-time', this.windowMs); return now; } const createTime = await this.client.get(key + '-create-time'); return parseInt(createTime as string); } }