From 0d9a4eccb48a69392177a07d662156be7299cac2 Mon Sep 17 00:00:00 2001 From: Slava Fomin Date: Sun, 24 Nov 2024 01:21:48 +0300 Subject: [PATCH 1/3] Added `keyPrefix` option, plus some trivial fixes Signed-off-by: Slava Fomin --- .gitignore | 1 + src/rateLimiter.ts | 11 ++++++----- src/typesAndDefaults.ts | 15 +++++++++++---- 3 files changed, 18 insertions(+), 9 deletions(-) diff --git a/.gitignore b/.gitignore index e9d079f..b9cd518 100644 --- a/.gitignore +++ b/.gitignore @@ -1,3 +1,4 @@ +/.idea/ node_modules/ package-lock.json *.tsbuildinfo diff --git a/src/rateLimiter.ts b/src/rateLimiter.ts index e05611c..ea0c002 100644 --- a/src/rateLimiter.ts +++ b/src/rateLimiter.ts @@ -29,19 +29,20 @@ import { RedisStore } from "./redisStore.ts"; export const limit = ( userOptions?: OptionsInterface, ) => { - const options = { ...defaultOptions, ...userOptions }; + const options = { ...defaultOptions, ...(userOptions ?? {}) }; const store = options.storageClient === "MEMORY_STORE" ? new MemoryStore(options.timeFrame) : new RedisStore(options.storageClient as RT, options.timeFrame); + const keyPrefix = userOptions?.keyPrefix ?? defaultOptions.keyPrefix; + const middlewareFunc = async (ctx: C, next: NextFunction) => { - const keyCheck = options.keyGenerator(ctx); - if (!keyCheck) { + const key = options.keyGenerator(ctx); + if (!key) { return await next(); } - const key = "RATE_LIMITER" + keyCheck; - const hits = await store.increment(key); + const hits = await store.increment(keyPrefix + key); if (hits === options.limit + 1 || (options.alwaysReply && hits > options.limit)) { return options.onLimitExceeded(ctx, next); diff --git a/src/typesAndDefaults.ts b/src/typesAndDefaults.ts index 66ba278..1983cae 100644 --- a/src/typesAndDefaults.ts +++ b/src/typesAndDefaults.ts @@ -54,17 +54,24 @@ export interface OptionsInterface { /** * @param ctx Is the context object you get from grammy/telegraf. - * @returns A number in **string** format as the unique key (identifier). - * @description A function to generate a unique key for every user. You cound set it as any key you want (e.g group id) + * @returns A unique **string** key (identifier). + * @description A function to generate a unique key for every user. You could set it as any key you want (e.g. group id) * @see [Getting Started](https://github.com/Amir-Zouerami/rateLimiter#-how-to-use) */ keyGenerator?: (ctx: C) => string | undefined; + + /** + * @default "RATE_LIMITER" + * @description A string prefix that is getting added to the storage key after calling the `keyGenerator()`. + */ + keyPrefix?: string | undefined; } -export const defaultOptions = { +export const defaultOptions: OptionsInterface = { timeFrame: 1000, limit: 1, onLimitExceeded: (_ctx: Context, _next: NextFunction) => {}, storageClient: "MEMORY_STORE", - keyGenerator: (ctx: Context) => ctx.from === undefined ? undefined : ctx.from.id.toString(), + keyGenerator: (ctx: Context) => ctx.from?.id.toString(), + keyPrefix: "RATE_LIMITER", }; From 2462125125dcbe4b5693853d10a57519679aba93 Mon Sep 17 00:00:00 2001 From: Slava Fomin Date: Sun, 24 Nov 2024 20:41:05 +0300 Subject: [PATCH 2/3] Removed extraneous undefined guard Signed-off-by: Slava Fomin --- src/rateLimiter.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/rateLimiter.ts b/src/rateLimiter.ts index ea0c002..afa8069 100644 --- a/src/rateLimiter.ts +++ b/src/rateLimiter.ts @@ -29,7 +29,7 @@ import { RedisStore } from "./redisStore.ts"; export const limit = ( userOptions?: OptionsInterface, ) => { - const options = { ...defaultOptions, ...(userOptions ?? {}) }; + const options = { ...defaultOptions, ...userOptions }; const store = options.storageClient === "MEMORY_STORE" ? new MemoryStore(options.timeFrame) : new RedisStore(options.storageClient as RT, options.timeFrame); From fedf4c3e3aa4f2133cd0c78bab565a983029ebcb Mon Sep 17 00:00:00 2001 From: Slava Fomin Date: Sun, 24 Nov 2024 20:50:44 +0300 Subject: [PATCH 3/3] Fixed `defaultOptions` typing Signed-off-by: Slava Fomin --- src/typesAndDefaults.ts | 13 ++++++++++++- 1 file changed, 12 insertions(+), 1 deletion(-) diff --git a/src/typesAndDefaults.ts b/src/typesAndDefaults.ts index 1983cae..9f878e1 100644 --- a/src/typesAndDefaults.ts +++ b/src/typesAndDefaults.ts @@ -67,7 +67,18 @@ export interface OptionsInterface { keyPrefix?: string | undefined; } -export const defaultOptions: OptionsInterface = { +type DefaultOptions = Required, ( + | 'timeFrame' + | 'limit' + | 'onLimitExceeded' + | 'storageClient' + | 'keyGenerator' + | 'keyPrefix' + )> +>; + +export const defaultOptions: DefaultOptions = { timeFrame: 1000, limit: 1, onLimitExceeded: (_ctx: Context, _next: NextFunction) => {},