UNPKG

@adonisjs/limiter

Version:

Rate limiting package for AdonisJS framework

136 lines (135 loc) 4.75 kB
import { RateLimiterRes, type RateLimiterAbstract, type RateLimiterStoreAbstract } from 'rate-limiter-flexible'; import { LimiterResponse } from '../response.ts'; import type { LimiterStoreContract } from '../types.ts'; /** * Bridge class that adapts rate-limiter-flexible stores to work with AdonisJS limiter. * This class provides a consistent interface for all limiter stores. * * When creating custom stores that wrap rate-limiter-flexible implementations, * extend this class to inherit the standard AdonisJS limiter behavior. */ export default abstract class RateLimiterBridge implements LimiterStoreContract { protected rateLimiter: RateLimiterStoreAbstract | RateLimiterAbstract; /** * A unique name for the store */ abstract readonly name: string; /** * The number of configured requests on the store */ get requests(): number; /** * The duration (in seconds) for which the requests are configured */ get duration(): number; /** * The duration (in seconds) for which to block the key */ get blockDuration(): number; constructor(rateLimiter: RateLimiterStoreAbstract | RateLimiterAbstract); /** * Clears the store database, removing all rate limit data. * Implementation varies by store type. */ abstract clear(): Promise<void>; /** * Transforms a rate-limiter-flexible response into an AdonisJS LimiterResponse. * * @param response - Raw response from rate-limiter-flexible */ protected makeLimiterResponse(response: RateLimiterRes): LimiterResponse; /** * Consumes one request for the given key. Throws a ThrottleException * when the rate limit is exceeded or the key is blocked. * * @param key - Unique identifier for the rate limit (e.g., user ID, IP address) * * @example * ```ts * const response = await limiter.consume('user:123') * console.log(`Remaining: ${response.remaining}`) * ``` */ consume(key: string | number, amount?: number): Promise<LimiterResponse>; /** * Increments the consumed request count for the given key. * Unlike consume(), this method does not throw when the limit is reached. * * @param key - Unique identifier for the rate limit * * @example * ```ts * const response = await limiter.increment('user:123') * ``` */ increment(key: string | number, amount?: number): Promise<LimiterResponse>; /** * Decrements the consumed request count for the given key. * Will not decrement below zero. * * @param key - Unique identifier for the rate limit * * @example * ```ts * const response = await limiter.decrement('user:123') * ``` */ decrement(key: string | number, amount?: number): Promise<LimiterResponse>; /** * Blocks the given key for the specified duration, preventing any requests. * * @param key - Unique identifier for the rate limit * @param duration - Block duration in seconds or as a time expression (e.g., '5 mins') * * @example * ```ts * await limiter.block('user:123', '10 mins') * await limiter.block('ip:192.168.1.1', 600) * ``` */ block(key: string | number, duration: string | number): Promise<LimiterResponse>; /** * Manually sets the number of consumed requests for a given key. * * @param key - Unique identifier for the rate limit * @param requests - Number of requests consumed * @param duration - Optional duration in seconds or time expression * * @example * ```ts * // Set that user has consumed 20 requests out of 25 allowed * await limiter.set('user:123', 20, '1 minute') * ``` */ set(key: string | number, requests: number, duration?: string | number): Promise<LimiterResponse>; /** * Deletes the given key, resetting its rate limit state. * * @param key - Unique identifier for the rate limit * * @example * ```ts * await limiter.delete('user:123') * ``` */ delete(key: string | number): Promise<boolean>; /** * Deletes all keys that are blocked in memory. * Only applicable for stores with in-memory blocking enabled. */ deleteInMemoryBlockedKeys(): void; /** * Retrieves the current rate limit state for the given key. * * @param key - Unique identifier for the rate limit * * @example * ```ts * const response = await limiter.get('user:123') * if (response) { * console.log(`Remaining: ${response.remaining}`) * } * ``` */ get(key: string | number): Promise<LimiterResponse | null>; }