diff --git a/src/helpers/commands/create_slash_command.ts b/src/helpers/commands/create_slash_command.ts index fafa506fb..8baa84490 100644 --- a/src/helpers/commands/create_slash_command.ts +++ b/src/helpers/commands/create_slash_command.ts @@ -1,7 +1,11 @@ import { applicationId } from "../../bot.ts"; import { rest } from "../../rest/rest.ts"; +import { CreateGlobalApplicationCommand } from "../../types/interactions/create_global_application_command.ts"; import { endpoints } from "../../util/constants.ts"; -import { validateSlashCommands } from "../../util/utils.ts"; +import { + camelKeysToSnakeCase, + validateSlashCommands, +} from "../../util/utils.ts"; /** * There are two kinds of Slash Commands: global commands and guild commands. Global commands are available for every guild that adds your app; guild commands are specific to the guild you specify when making them. Command names are unique per application within each scope (global and guild). That means: @@ -14,17 +18,18 @@ import { validateSlashCommands } from "../../util/utils.ts"; * Global commands are cached for **1 hour**. That means that new global commands will fan out slowly across all guilds, and will be guaranteed to be updated in an hour. * Guild commands update **instantly**. We recommend you use guild commands for quick testing, and global commands when they're ready for public use. */ -export async function createSlashCommand(options: CreateSlashCommandOptions) { +export async function createSlashCommand( + options: CreateGlobalApplicationCommand, + guildId: string, +) { validateSlashCommands([options], true); const result = await rest.runMethod( "post", - options.guildId - ? endpoints.COMMANDS_GUILD(applicationId, options.guildId) + guildId + ? endpoints.COMMANDS_GUILD(applicationId, guildId) : endpoints.COMMANDS(applicationId), - { - ...options, - }, + camelKeysToSnakeCase(options), ); return result; diff --git a/src/helpers/commands/delete_slash_command.ts b/src/helpers/commands/delete_slash_command.ts index 1eda08083..0b9580e15 100644 --- a/src/helpers/commands/delete_slash_command.ts +++ b/src/helpers/commands/delete_slash_command.ts @@ -3,12 +3,16 @@ import { rest } from "../../rest/rest.ts"; import { endpoints } from "../../util/constants.ts"; /** Deletes a slash command. */ -export function deleteSlashCommand(id: string, guildId?: string) { - if (!guildId) { - return rest.runMethod("delete", endpoints.COMMANDS_ID(applicationId, id)); - } - return rest.runMethod( +export async function deleteSlashCommand( + id: string, + guildId?: string, +): Promise { + const result = await rest.runMethod( "delete", - endpoints.COMMANDS_GUILD_ID(applicationId, guildId, id), + guildId + ? endpoints.COMMANDS_GUILD_ID(applicationId, guildId, id) + : endpoints.COMMANDS_ID(applicationId, id), ); + + return result; } diff --git a/src/helpers/commands/delete_slash_response.ts b/src/helpers/commands/delete_slash_response.ts index 1a9d480e0..14523c3a5 100644 --- a/src/helpers/commands/delete_slash_response.ts +++ b/src/helpers/commands/delete_slash_response.ts @@ -3,7 +3,10 @@ import { rest } from "../../rest/rest.ts"; import { endpoints } from "../../util/constants.ts"; /** To delete your response to a slash command. If a message id is not provided, it will default to deleting the original response. */ -export async function deleteSlashResponse(token: string, messageId?: string) { +export async function deleteSlashResponse( + token: string, + messageId?: string, +): Promise { const result = await rest.runMethod( "delete", messageId diff --git a/src/helpers/commands/edit_slash_response.ts b/src/helpers/commands/edit_slash_response.ts index fa81ac460..f3c49f34d 100644 --- a/src/helpers/commands/edit_slash_response.ts +++ b/src/helpers/commands/edit_slash_response.ts @@ -1,13 +1,16 @@ import { applicationId } from "../../bot.ts"; import { rest } from "../../rest/rest.ts"; import { structures } from "../../structures/mod.ts"; +import { DiscordenoEditWebhookMessage } from "../../types/discordeno/edit_webhook_message.ts"; +import { DiscordAllowedMentionsTypes } from "../../types/messages/allowed_mentions_types.ts"; +import { DiscordMessage } from "../../types/messages/message.ts"; import { Errors } from "../../types/misc/errors.ts"; import { endpoints } from "../../util/constants.ts"; /** To edit your response to a slash command. If a messageId is not provided it will default to editing the original response. */ export async function editSlashResponse( token: string, - options: EditSlashResponseOptions, + options: DiscordenoEditWebhookMessage, ) { if (options.content && options.content.length > 2000) { throw Error(Errors.MESSAGE_MAX_LENGTH); @@ -17,31 +20,39 @@ export async function editSlashResponse( options.embeds.splice(10); } - if (options.allowed_mentions) { - if (options.allowed_mentions.users?.length) { - if (options.allowed_mentions.parse.includes("users")) { - options.allowed_mentions.parse = options.allowed_mentions.parse.filter( + if (options.allowedMentions) { + if (options.allowedMentions.users?.length) { + if ( + options.allowedMentions.parse.includes( + DiscordAllowedMentionsTypes.UserMentions, + ) + ) { + options.allowedMentions.parse = options.allowedMentions.parse.filter( (p) => p !== "users", ); } - if (options.allowed_mentions.users.length > 100) { - options.allowed_mentions.users = options.allowed_mentions.users.slice( + if (options.allowedMentions.users.length > 100) { + options.allowedMentions.users = options.allowedMentions.users.slice( 0, 100, ); } } - if (options.allowed_mentions.roles?.length) { - if (options.allowed_mentions.parse.includes("roles")) { - options.allowed_mentions.parse = options.allowed_mentions.parse.filter( + if (options.allowedMentions.roles?.length) { + if ( + options.allowedMentions.parse.includes( + DiscordAllowedMentionsTypes.RoleMentions, + ) + ) { + options.allowedMentions.parse = options.allowedMentions.parse.filter( (p) => p !== "roles", ); } - if (options.allowed_mentions.roles.length > 100) { - options.allowed_mentions.roles = options.allowed_mentions.roles.slice( + if (options.allowedMentions.roles.length > 100) { + options.allowedMentions.roles = options.allowedMentions.roles.slice( 0, 100, ); @@ -61,7 +72,7 @@ export async function editSlashResponse( if (!options.messageId) return result; const message = await structures.createMessageStruct( - result as MessageCreateOptions, + result as DiscordMessage, ); return message; } diff --git a/src/helpers/commands/get_slash_command.ts b/src/helpers/commands/get_slash_command.ts index 3cc50bc28..72c61b3f6 100644 --- a/src/helpers/commands/get_slash_command.ts +++ b/src/helpers/commands/get_slash_command.ts @@ -1,5 +1,6 @@ import { applicationId } from "../../bot.ts"; import { rest } from "../../rest/rest.ts"; +import { ApplicationCommand } from "../../types/interactions/application_command.ts"; import { endpoints } from "../../util/constants.ts"; /** Fetchs the global command for the given Id. If a guildId is provided, the guild command will be fetched. */ @@ -11,5 +12,5 @@ export async function getSlashCommand(commandId: string, guildId?: string) { : endpoints.COMMANDS_ID(applicationId, commandId), ); - return result as SlashCommand; + return result as ApplicationCommand; } diff --git a/src/helpers/commands/get_slash_commands.ts b/src/helpers/commands/get_slash_commands.ts index ce2cc50bf..3337baf49 100644 --- a/src/helpers/commands/get_slash_commands.ts +++ b/src/helpers/commands/get_slash_commands.ts @@ -1,5 +1,6 @@ import { applicationId } from "../../bot.ts"; import { rest } from "../../rest/rest.ts"; +import { ApplicationCommand } from "../../types/interactions/application_command.ts"; import { Collection } from "../../util/collection.ts"; import { endpoints } from "../../util/constants.ts"; @@ -10,7 +11,7 @@ export async function getSlashCommands(guildId?: string) { guildId ? endpoints.COMMANDS_GUILD(applicationId, guildId) : endpoints.COMMANDS(applicationId), - )) as SlashCommand[]; + )) as ApplicationCommand[]; return new Collection(result.map((command) => [command.name, command])); } diff --git a/src/helpers/commands/send_interaction_response.ts b/src/helpers/commands/send_interaction_response.ts index c60ea83ef..6d9fb0022 100644 --- a/src/helpers/commands/send_interaction_response.ts +++ b/src/helpers/commands/send_interaction_response.ts @@ -1,6 +1,7 @@ import { applicationId } from "../../bot.ts"; import { cache } from "../../cache.ts"; import { rest } from "../../rest/rest.ts"; +import { DiscordenoInteractionResponse } from "../../types/discordeno/interaction_response.ts"; import { endpoints } from "../../util/constants.ts"; /** @@ -12,7 +13,7 @@ import { endpoints } from "../../util/constants.ts"; export async function sendInteractionResponse( id: string, token: string, - options: SlashCommandResponseOptions, + options: DiscordenoInteractionResponse, ) { // If its already been executed, we need to send a followup response if (cache.executedSlashCommands.has(token)) { @@ -30,12 +31,12 @@ export async function sendInteractionResponse( // If the user wants this as a private message mark it ephemeral if (options.private) { - options.data.flags = 64; + options.data = { ...options.data, flags: 64 }; } // If no mentions are provided, force disable mentions - if (!options.data.allowed_mentions) { - options.data.allowed_mentions = { parse: [] }; + if (!options.data?.allowedMentions) { + options.data = { ...options.data, allowedMentions: { parse: [] } }; } const result = await rest.runMethod( diff --git a/src/helpers/commands/upsert_slash_command.ts b/src/helpers/commands/upsert_slash_command.ts index 21091f18e..66c064780 100644 --- a/src/helpers/commands/upsert_slash_command.ts +++ b/src/helpers/commands/upsert_slash_command.ts @@ -1,5 +1,6 @@ import { applicationId } from "../../bot.ts"; import { rest } from "../../rest/rest.ts"; +import { EditGlobalApplicationCommand } from "../../types/interactions/edit_global_application_command.ts"; import { endpoints } from "../../util/constants.ts"; import { validateSlashCommands } from "../../util/utils.ts"; @@ -8,7 +9,7 @@ import { validateSlashCommands } from "../../util/utils.ts"; */ export async function upsertSlashCommand( commandId: string, - options: UpsertSlashCommandOptions, + options: EditGlobalApplicationCommand, guildId?: string, ) { validateSlashCommands([options]); diff --git a/src/helpers/commands/upsert_slash_commands.ts b/src/helpers/commands/upsert_slash_commands.ts index a5befc957..ce0bdeee2 100644 --- a/src/helpers/commands/upsert_slash_commands.ts +++ b/src/helpers/commands/upsert_slash_commands.ts @@ -1,5 +1,6 @@ import { applicationId } from "../../bot.ts"; import { rest } from "../../rest/rest.ts"; +import { EditGlobalApplicationCommand } from "../../types/interactions/edit_global_application_command.ts"; import { endpoints } from "../../util/constants.ts"; import { validateSlashCommands } from "../../util/utils.ts"; @@ -9,7 +10,7 @@ import { validateSlashCommands } from "../../util/utils.ts"; * **NOTE:** Any slash commands that are not specified in this function will be **deleted**. If you don't provide the commandId and rename your command, the command gets a new Id. */ export async function upsertSlashCommands( - options: UpsertSlashCommandsOptions[], + options: EditGlobalApplicationCommand[], guildId?: string, ) { validateSlashCommands(options); diff --git a/src/helpers/emojis/create_emoji.ts b/src/helpers/emojis/create_emoji.ts index 1070bf7a9..4b2cdff67 100644 --- a/src/helpers/emojis/create_emoji.ts +++ b/src/helpers/emojis/create_emoji.ts @@ -1,14 +1,16 @@ import { rest } from "../../rest/rest.ts"; +import { CreateGuildEmoji } from "../../types/emojis/create_guild_emoji.ts"; +import { Emoji } from "../../types/emojis/emoji.ts"; import { endpoints } from "../../util/constants.ts"; import { requireBotGuildPermissions } from "../../util/permissions.ts"; -import { urlToBase64 } from "../../util/utils.ts"; +import { snakeKeysToCamelCase, urlToBase64 } from "../../util/utils.ts"; /** Create an emoji in the server. Emojis and animated emojis have a maximum file size of 256kb. Attempting to upload an emoji larger than this limit will fail and return 400 Bad Request and an error message, but not a JSON status code. If a URL is provided to the image parameter, Discordeno will automatically convert it to a base64 string internally. */ export async function createEmoji( guildId: string, name: string, image: string, - options: CreateEmojisOptions, + options: CreateGuildEmoji, ) { await requireBotGuildPermissions(guildId, ["MANAGE_EMOJIS"]); @@ -22,5 +24,5 @@ export async function createEmoji( image, }); - return result; + return snakeKeysToCamelCase(result) as Emoji; } diff --git a/src/helpers/emojis/delete_emoji.ts b/src/helpers/emojis/delete_emoji.ts index 64154ccfe..97783b41c 100644 --- a/src/helpers/emojis/delete_emoji.ts +++ b/src/helpers/emojis/delete_emoji.ts @@ -7,7 +7,7 @@ export async function deleteEmoji( guildId: string, id: string, reason?: string, -) { +): Promise { await requireBotGuildPermissions(guildId, ["MANAGE_EMOJIS"]); const result = await rest.runMethod( diff --git a/src/helpers/emojis/edit_emoji.ts b/src/helpers/emojis/edit_emoji.ts index 0c2e125a6..803dc8ea5 100644 --- a/src/helpers/emojis/edit_emoji.ts +++ b/src/helpers/emojis/edit_emoji.ts @@ -1,4 +1,5 @@ import { rest } from "../../rest/rest.ts"; +import { ModifyGuildEmoji } from "../../types/emojis/modify_guild_emoji.ts"; import { endpoints } from "../../util/constants.ts"; import { requireBotGuildPermissions } from "../../util/permissions.ts"; @@ -6,7 +7,7 @@ import { requireBotGuildPermissions } from "../../util/permissions.ts"; export async function editEmoji( guildId: string, id: string, - options: EditEmojisOptions, + options: ModifyGuildEmoji, ) { await requireBotGuildPermissions(guildId, ["MANAGE_EMOJIS"]); diff --git a/src/helpers/emojis/get_emoji.ts b/src/helpers/emojis/get_emoji.ts index edf3f4c25..c99baa1d0 100644 --- a/src/helpers/emojis/get_emoji.ts +++ b/src/helpers/emojis/get_emoji.ts @@ -1,5 +1,6 @@ import { cacheHandlers } from "../../cache.ts"; import { rest } from "../../rest/rest.ts"; +import { Emoji } from "../../types/emojis/emoji.ts"; import { Errors } from "../../types/misc/errors.ts"; import { endpoints } from "../../util/constants.ts"; @@ -21,7 +22,7 @@ export async function getEmoji( if (addToCache) { const guild = await cacheHandlers.get("guilds", guildId); if (!guild) throw new Error(Errors.GUILD_NOT_FOUND); - guild.emojis.set(result.id ?? result.name, result); + guild.emojis.set(emojiId, result); cacheHandlers.set( "guilds", guildId, diff --git a/src/helpers/emojis/get_emojis.ts b/src/helpers/emojis/get_emojis.ts index 133723114..6678c2b81 100644 --- a/src/helpers/emojis/get_emojis.ts +++ b/src/helpers/emojis/get_emojis.ts @@ -1,5 +1,6 @@ import { cacheHandlers } from "../../cache.ts"; import { rest } from "../../rest/rest.ts"; +import { Emoji } from "../../types/emojis/emoji.ts"; import { Errors } from "../../types/misc/errors.ts"; import { endpoints } from "../../util/constants.ts"; @@ -16,7 +17,7 @@ export async function getEmojis(guildId: string, addToCache = true) { const guild = await cacheHandlers.get("guilds", guildId); if (!guild) throw new Error(Errors.GUILD_NOT_FOUND); - result.forEach((emoji) => guild.emojis.set(emoji.id ?? emoji.name, emoji)); + result.forEach((emoji) => guild.emojis.set(emoji.id!, emoji)); cacheHandlers.set("guilds", guildId, guild); } diff --git a/src/helpers/guilds/create_guild.ts b/src/helpers/guilds/create_guild.ts index 144d260a4..cb58b92ac 100644 --- a/src/helpers/guilds/create_guild.ts +++ b/src/helpers/guilds/create_guild.ts @@ -1,14 +1,16 @@ import { rest } from "../../rest/rest.ts"; import { structures } from "../../structures/mod.ts"; +import { CreateGuild } from "../../types/guilds/create_guild.ts"; +import { DiscordGuild } from "../../types/guilds/guild.ts"; import { endpoints } from "../../util/constants.ts"; /** Create a new guild. Returns a guild object on success. Fires a Guild Create Gateway event. This endpoint can be used only by bots in less than 10 guilds. */ -export async function createGuild(options: CreateServerOptions) { +export async function createGuild(options: CreateGuild) { const guild = (await rest.runMethod( "post", endpoints.GUILDS, options, - )) as CreateGuildPayload; + )) as DiscordGuild; return structures.createGuildStruct(guild, 0); } diff --git a/src/helpers/guilds/delete_server.ts b/src/helpers/guilds/delete_server.ts index 03da1f717..43a1085eb 100644 --- a/src/helpers/guilds/delete_server.ts +++ b/src/helpers/guilds/delete_server.ts @@ -3,7 +3,7 @@ import { endpoints } from "../../util/constants.ts"; /** Delete a guild permanently. User must be owner. Returns 204 No Content on success. Fires a Guild Delete Gateway event. */ -export async function deleteServer(guildId: string) { +export async function deleteServer(guildId: string): Promise { const result = await rest.runMethod("delete", endpoints.GUILDS_BASE(guildId)); return result; diff --git a/src/helpers/guilds/edit_guild.ts b/src/helpers/guilds/edit_guild.ts index 081b7a64b..a45217594 100644 --- a/src/helpers/guilds/edit_guild.ts +++ b/src/helpers/guilds/edit_guild.ts @@ -1,10 +1,13 @@ import { rest } from "../../rest/rest.ts"; +import { structures } from "../../structures/mod.ts"; +import { DiscordGuild } from "../../types/guilds/guild.ts"; +import { ModifyGuild } from "../../types/guilds/modify_guild.ts"; import { endpoints } from "../../util/constants.ts"; import { requireBotGuildPermissions } from "../../util/permissions.ts"; import { urlToBase64 } from "../../util/utils.ts"; /** Modify a guilds settings. Requires the MANAGE_GUILD permission. */ -export async function editGuild(guildId: string, options: GuildEditOptions) { +export async function editGuild(guildId: string, options: ModifyGuild) { await requireBotGuildPermissions(guildId, ["MANAGE_GUILD"]); if (options.icon && !options.icon.startsWith("data:image/")) { @@ -23,7 +26,7 @@ export async function editGuild(guildId: string, options: GuildEditOptions) { "patch", endpoints.GUILDS_BASE(guildId), options, - ); + ) as DiscordGuild; - return result; + return structures.createGuildStruct(result, -1); } diff --git a/src/helpers/guilds/edit_widget.ts b/src/helpers/guilds/edit_widget.ts index f36511cc7..42eaefd1b 100644 --- a/src/helpers/guilds/edit_widget.ts +++ b/src/helpers/guilds/edit_widget.ts @@ -1,6 +1,8 @@ import { rest } from "../../rest/rest.ts"; +import { GuildWidget } from "../../types/guilds/guild_widget.ts"; import { endpoints } from "../../util/constants.ts"; import { requireBotGuildPermissions } from "../../util/permissions.ts"; +import { snakeKeysToCamelCase } from "../../util/utils.ts"; /** Modify a guild widget object for the guild. Requires the MANAGE_GUILD permission. */ export async function editWidget( @@ -19,5 +21,5 @@ export async function editWidget( }, ); - return result; + return snakeKeysToCamelCase(result) as GuildWidget; } diff --git a/src/helpers/messages/send_message.ts b/src/helpers/messages/send_message.ts index b7c628917..e80f5ff72 100644 --- a/src/helpers/messages/send_message.ts +++ b/src/helpers/messages/send_message.ts @@ -2,15 +2,19 @@ import { cacheHandlers } from "../../cache.ts"; import { rest } from "../../rest/rest.ts"; import { structures } from "../../structures/mod.ts"; import { DiscordChannelTypes } from "../../types/channels/channel_types.ts"; +import { DiscordenoCreateMessage } from "../../types/discordeno/create_message.ts"; +import { DiscordAllowedMentionsTypes } from "../../types/messages/allowed_mentions_types.ts"; +import { DiscordMessage } from "../../types/messages/message.ts"; import { Errors } from "../../types/misc/errors.ts"; import { PermissionStrings } from "../../types/permissions/permission_strings.ts"; import { endpoints } from "../../util/constants.ts"; import { requireBotChannelPermissions } from "../../util/permissions.ts"; +import { camelKeysToSnakeCase } from "../../util/utils.ts"; /** Send a message to the channel. Requires SEND_MESSAGES permission. */ export async function sendMessage( channelId: string, - content: string | MessageContent, + content: string | DiscordenoCreateMessage, ) { if (typeof content === "string") content = { content }; @@ -33,7 +37,10 @@ export async function sendMessage( if (content.tts) requiredPerms.add("SEND_TTS_MESSAGES"); if (content.embed) requiredPerms.add("EMBED_LINKS"); - if (content.replyMessageId || content.mentions?.repliedUser) { + if ( + content.messageReference?.messageId || + content.allowedMentions?.repliedUser + ) { requiredPerms.add("READ_MESSAGE_HISTORY"); } @@ -45,50 +52,63 @@ export async function sendMessage( throw new Error(Errors.MESSAGE_MAX_LENGTH); } - if (content.mentions) { - if (content.mentions.users?.length) { - if (content.mentions.parse?.includes("users")) { - content.mentions.parse = content.mentions.parse.filter( + if (content.allowedMentions) { + if (content.allowedMentions.users?.length) { + if ( + content.allowedMentions.parse?.includes( + DiscordAllowedMentionsTypes.UserMentions, + ) + ) { + content.allowedMentions.parse = content.allowedMentions.parse.filter( (p) => p !== "users", ); } - if (content.mentions.users.length > 100) { - content.mentions.users = content.mentions.users.slice(0, 100); + if (content.allowedMentions.users.length > 100) { + content.allowedMentions.users = content.allowedMentions.users.slice( + 0, + 100, + ); } } - if (content.mentions.roles?.length) { - if (content.mentions.parse?.includes("roles")) { - content.mentions.parse = content.mentions.parse.filter( + if (content.allowedMentions.roles?.length) { + if ( + content.allowedMentions.parse?.includes( + DiscordAllowedMentionsTypes.RoleMentions, + ) + ) { + content.allowedMentions.parse = content.allowedMentions.parse.filter( (p) => p !== "roles", ); } - if (content.mentions.roles.length > 100) { - content.mentions.roles = content.mentions.roles.slice(0, 100); + if (content.allowedMentions.roles.length > 100) { + content.allowedMentions.roles = content.allowedMentions.roles.slice( + 0, + 100, + ); } } } const result = - (await rest.runMethod("post", endpoints.CHANNEL_MESSAGES(channelId), { - ...content, - allowed_mentions: content.mentions - ? { - ...content.mentions, - replied_user: content.mentions.repliedUser, - } - : undefined, - ...(content.replyMessageId - ? { - message_reference: { - message_id: content.replyMessageId, - fail_if_not_exists: content.failReplyIfNotExists === true, - }, - } - : {}), - })) as MessageCreateOptions; + (await rest.runMethod( + "post", + endpoints.CHANNEL_MESSAGES(channelId), + camelKeysToSnakeCase({ + ...content, + ...(content.messageReference?.messageId + ? { + messageReference: { + ...content.messageReference, + failIfNotExists: + content.messageReference.failIfNotExists === true, + }, + } + : {}), + }), + )) as DiscordMessage; return structures.createMessageStruct(result); } diff --git a/src/helpers/messages/unpin_message.ts b/src/helpers/messages/unpin_message.ts index db19544ef..c2a5630bf 100644 --- a/src/helpers/messages/unpin_message.ts +++ b/src/helpers/messages/unpin_message.ts @@ -3,7 +3,10 @@ import { endpoints } from "../../util/constants.ts"; import { requireBotChannelPermissions } from "../../util/permissions.ts"; /** Unpin a message in a channel. Requires MANAGE_MESSAGES. */ -export async function unpin(channelId: string, messageId: string) { +export async function unpin( + channelId: string, + messageId: string, +): Promise { await requireBotChannelPermissions(channelId, ["MANAGE_MESSAGES"]); const result = await rest.runMethod(