diff --git a/src/handlers/command-handler/validations/cooldown.ts b/src/handlers/command-handler/validations/cooldown.ts new file mode 100644 index 00000000..464480bc --- /dev/null +++ b/src/handlers/command-handler/validations/cooldown.ts @@ -0,0 +1,37 @@ +import { BuiltInValidationParams } from "@/types.js"; + +const cooldowns = new Map>(); + +export default function ({ targetCommand, interaction }: BuiltInValidationParams) { + const { cooldown } = targetCommand.options || {}; + + if (!cooldown) return; + + const now = Date.now(); + const userId = interaction.user.id; + const commandName = targetCommand.data.name; + + if (!cooldowns.has(commandName)) { + cooldowns.set(commandName, new Map()); + } + + const userCooldowns = cooldowns.get(commandName)!; + + if (userCooldowns) { + const expirationTime = userCooldowns.get(userId)! + cooldown * 1000; + if (now < expirationTime) { + const timeLeft = (expirationTime - now) / 1000; + + if (!interaction.isRepliable()) return; + + interaction.reply({ + content: `❌ You can use this command again in ${timeLeft.toFixed(1)} seconds.`, + ephemeral: true, + }); + + return true; + } + } + userCooldowns.set(userId, now); + return false; +} diff --git a/src/handlers/command-handler/validations/index.ts b/src/handlers/command-handler/validations/index.ts index 13ceccc7..c4e6dc58 100644 --- a/src/handlers/command-handler/validations/index.ts +++ b/src/handlers/command-handler/validations/index.ts @@ -1,3 +1,4 @@ import devOnly from "./devOnly.js"; +import cooldown from "./cooldown.js"; -export default [devOnly]; +export default [devOnly, cooldown]; diff --git a/src/types.d.ts b/src/types.d.ts index 4b2e3325..2ff3cfd0 100644 --- a/src/types.d.ts +++ b/src/types.d.ts @@ -49,6 +49,7 @@ export interface CommandContext<_T extends Interaction, _Cached extends CacheTyp export interface CommandOptions { devOnly?: boolean; + cooldown?: number; } export interface CommandFileObject {