diff --git a/src/handlers/command-handler/index.ts b/src/handlers/command-handler/index.ts index 93c6ebd0..af34a199 100644 --- a/src/handlers/command-handler/index.ts +++ b/src/handlers/command-handler/index.ts @@ -4,11 +4,14 @@ import { getFilePaths } from "@/utils/get-path.js"; import { toFileURL } from "@/utils/resolve-file.js"; import registerCommands from "./functions/registerCommands.js"; import { ExtendedClient } from "@/structures/client.js"; -import { CommandFileObject } from "@//types.js"; +import { BuiltInValidation, CommandFileObject } from "@/types.js"; +import builtInValidationsFunctions from "./validations/index.js"; export class CommandHandler { client: ExtendedClient; commands: CommandFileObject[] = []; + builtInValidations: BuiltInValidation[] = []; + constructor(client: ExtendedClient) { this.client = client; } @@ -16,6 +19,8 @@ export class CommandHandler { async init() { await this.#buildCommands(); + this.buildBuiltInValidations(); + await registerCommands({ client: this.client, commands: this.commands, @@ -45,6 +50,12 @@ export class CommandHandler { } } + buildBuiltInValidations() { + for (const builtInValidationFunction of builtInValidationsFunctions) { + this.builtInValidations.push(builtInValidationFunction); + } + } + handleCommands() { this.client.on("interactionCreate", async interaction => { if (!interaction.isChatInputCommand() && !interaction.isAutocomplete()) return; @@ -58,6 +69,23 @@ export class CommandHandler { // Skip if autocomplete handler is not defined if (isAutocomplete && !targetCommand.autocompleteRun) return; + let canRun = true; + + for (const validation of this.builtInValidations) { + const stopValidationLoop = validation({ + targetCommand, + interaction, + client: this.client, + }); + + if (stopValidationLoop) { + canRun = false; + break; + } + } + + if (!canRun) return; + const command = targetCommand[isAutocomplete ? "autocompleteRun" : "run"]!; try { diff --git a/src/handlers/command-handler/validations/devOnly.ts b/src/handlers/command-handler/validations/devOnly.ts new file mode 100644 index 00000000..ce8bdbbd --- /dev/null +++ b/src/handlers/command-handler/validations/devOnly.ts @@ -0,0 +1,18 @@ +import { BuiltInValidationParams } from "@/types.js"; + +export default function ({ interaction, targetCommand, client }: BuiltInValidationParams) { + if (interaction.isAutocomplete()) return; + + const devGuildsIds = client.configService.get("devGuildsIds"); + + if (!targetCommand.options?.devOnly) return; + + if (interaction.inGuild() && !devGuildsIds.includes(interaction.guildId)) { + interaction.reply({ + content: "❌ This command is only available in development servers.", + ephemeral: true, + }); + + return true; + } +} diff --git a/src/handlers/command-handler/validations/index.ts b/src/handlers/command-handler/validations/index.ts new file mode 100644 index 00000000..13ceccc7 --- /dev/null +++ b/src/handlers/command-handler/validations/index.ts @@ -0,0 +1,3 @@ +import devOnly from "./devOnly.js"; + +export default [devOnly]; diff --git a/src/types.d.ts b/src/types.d.ts index 96491a9d..4b2e3325 100644 --- a/src/types.d.ts +++ b/src/types.d.ts @@ -19,6 +19,14 @@ export type cacheRemindsData = { reminds: UserReminds[]; }; +export type BuiltInValidationParams = { + targetCommand: CommandFileObject; + interaction: Interaction; + client: ExtendedClient; +}; + +export type BuiltInValidation = ({}: BuiltInValidationParams) => boolean | void; + export type CronTaskData = { name: string; schedule: string;