rate-limiter-algorithms
Version:
Library that provides different algorithms to perform rate limiting
222 lines (217 loc) • 7.07 kB
text/typescript
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 };