UNPKG

rate-limiter-algorithms

Version:

Library that provides different algorithms to perform rate limiting

222 lines (217 loc) 7.07 kB
interface RateLimitAlgorithm<T extends AlgorithmValues> { /** * Maximum amount of points that client can consume */ limit: number; /** * Duration of time in milliseconds when algorithm updates its counter */ windowMs: number; /** * Store which contains clients data based on chosen algorithm */ store: ToStore<T>; /** * Consume points from a client's bucket. * @async * @param {string} clientId - The identifier for a client * @param {number} [weight=1] - Amount of points to consume per request. Defaults to 1 * @returns {Promise<boolean>} - Whether the client is allowed to proceed with the request. */ consume: (clientId: string, weight?: number) => Promise<ConsumeResult<T>>; } type ConsumeResult<T extends AlgorithmValues> = { /** * Is client allowed to proceed with request */ isAllowed: boolean; /** * An array of rate limit headers in pairs of [name,value] */ clientData: T; }; interface Store<T extends AlgorithmValues> { /** * Gets client data from a store * @async * @param {string} clientId - The identifier for a client * @returns {Promise<T | undefined>} - Client data from a store */ get: (clientId: string) => Promise<T | undefined>; /** * Saves client data in a store * @async * @param {string} clientId - The identifier for a client * @returns {Promise<T>} - Current client data */ set: (clientId: string, value: T) => Promise<T>; /** * Deletes client data from a store * @async * @param {string} clientId - The identifier for a client */ remove: (clientId: string) => Promise<void>; /** * Resets all clients data in a store * @async */ reset: () => Promise<void>; /** * Sets TTL - time period when expired clients will be removed in milliseconds */ setTTL: (TTL: number) => void; /** * Clean shutdown for the store */ shutdown?: () => Promise<void>; } type ToStore<T> = T extends AlgorithmValues ? Store<T> : never; type AlgorithmOptions<T extends AlgorithmValues> = { /** * Maximum amount of points that client can consume */ limit: number; /** * Duration of time in milliseconds when algorithm updates its counter */ windowMs: number; /** * Store which contains clients data based on chosen algorithm */ store?: Store<T>; }; type TokenBucketValues = { /** * Current number of points remaining to consume */ points: number; /** * Time in milliseconds when token bucket was last refilled */ lastRefillTimeMs: number; }; /** * Queue of timestamps ordered from lowest to highest */ type SlidingWindowLogValues = number[]; type SlidingWindowCounterValues = { /** * Points from previous window */ prevPoints: number; /** * Points from current window */ currPoints: number; /** * Time in milliseconds which separates previous and current windows */ edgeTimeMs: number; }; type FixedWindowCounterValues = { /** * Current number of points consumed */ points: number; /** * Time in milliseconds when window was updated */ lastWindowResetTimeMs: number; }; type AlgorithmValues = TokenBucketValues | SlidingWindowLogValues | SlidingWindowCounterValues | FixedWindowCounterValues; type TokenBucketConfig = AlgorithmOptions<TokenBucketValues>; type SlidingWindowLogConfig = AlgorithmOptions<SlidingWindowLogValues>; type SlidingWindowCounterConfig = AlgorithmOptions<SlidingWindowCounterValues>; type FixedWindowCounterConfig = AlgorithmOptions<FixedWindowCounterValues>; type TokenBucketOptions = { /** * Token bucket algorithm */ algorithm: "token-bucket"; } & TokenBucketConfig; type SlidingWindowCounterOptions = { /** * Sliding window counter algorithm */ algorithm: "sliding-window-counter"; } & SlidingWindowCounterConfig; type SlidingWindowLogsOptions = { /** * Sliding window logs algorithm */ algorithm: "sliding-window-logs"; } & SlidingWindowLogConfig; type FixedWindowCounterOptions = { /** * Fixed window counter algorithm */ algorithm: "fixed-window-counter"; } & FixedWindowCounterConfig; /** * @type {ConfigOptions} config * @property {string} algorithm - Algorithm type * @property {number} limit - Maximum amount of points client can consume * @property {number} windowMs - Duration of time in milliseconds when algorithm updates its counter * @property {Store | undefined} store - Store which contains clients data based on chosen algorithm */ type ConfigOptions = TokenBucketOptions | SlidingWindowCounterOptions | SlidingWindowLogsOptions | FixedWindowCounterOptions; declare class RateLimiter implements RateLimitAlgorithm<AlgorithmValues> { readonly limit: number; readonly windowMs: number; readonly store: ToStore<AlgorithmValues>; consume: (clientId: string, weight?: number) => Promise<ConsumeResult<AlgorithmValues>>; private getRemainingPoints; private getResetTime; /** * @constructor * @param {ConfigOptions} config - Rate limiter config options */ constructor(config: ConfigOptions); /** * Get rate limit headers for a client. * @param {AlgorithmValues} clientData - Retrieved data for a client * @returns {[string,string][]} - An array of rate limit headers in pairs of [name,value] */ getHeaders(clientData: AlgorithmValues): [string, string][]; private setDefaults; private getAlgorithm; private validateConfig; private checkForInvalidClientId; } declare class MemoryStore<T extends AlgorithmValues> implements Store<T> { /** * 'oldClients' are retained temporarily before being removed completely based on an interval timer. * Clients are moved from 'activeClients' to 'oldClients' when interval timer triggers. * Clients are moved from 'oldClients' to 'activeClients' when they are doing a request */ private oldClients; private activeClients; private TTL; private interval?; constructor(); get(clientId: string): Promise<T | undefined>; set(clientId: string, value: T): Promise<T>; remove(clientId: string): Promise<void>; reset(): Promise<void>; setTTL(TTL: number): void; shutdown(): Promise<void>; private clearExpired; } type RedisOptions = { rawCall: (...args: string[]) => Promise<unknown>; prefix?: string; }; declare class RedisStore<T extends AlgorithmValues> implements Store<T> { private prefix; private rawCall; private TTL; constructor(options: RedisOptions); get(clientId: string): Promise<T | undefined>; set(clientId: string, value: T): Promise<T>; remove(clientId: string): Promise<void>; reset(): Promise<void>; setTTL(TTL: number): void; private prefixedKey; shutdown(): Promise<void>; } export { MemoryStore, RateLimiter, RedisStore };