diff --git a/src/api/Routes/applications.ts b/src/api/Routes/applications.ts index eb9cf05..97d32a2 100644 --- a/src/api/Routes/applications.ts +++ b/src/api/Routes/applications.ts @@ -28,77 +28,69 @@ import type { RestArguments } from '../api'; import type { ProxyRequestMethod } from '../Router'; export interface ApplicationRoutes { - applications: { - ( - id: string, - ): { - guilds: { + applications: (id: string) => { + guilds: (id: string) => { + commands: { + get( + args?: RestArguments, + ): Promise; + post( + args: RestArguments, + ): Promise; + put( + args?: RestArguments, + ): Promise; + permissions: { + get( + args?: RestArguments, + ): Promise; + // put(args?: RestArguments): Promise + }; ( id: string, ): { - commands: { + get(args?: RestArguments): Promise; + patch( + args: RestArguments, + ): Promise; + delete(args?: RestArguments): Promise; + permissions: { get( - args?: RestArguments, - ): Promise; - post( - args: RestArguments, - ): Promise; + args?: RestArguments, + ): Promise; put( - args?: RestArguments, - ): Promise; - permissions: { - get( - args?: RestArguments, - ): Promise; - // put(args?: RestArguments): Promise - }; - ( - id: string, - ): { - get(args?: RestArguments): Promise; - patch( - args: RestArguments, - ): Promise; - delete(args?: RestArguments): Promise; - permissions: { - get( - args?: RestArguments, - ): Promise; - put( - args?: RestArguments, - ): Promise; - }; - }; + args?: RestArguments, + ): Promise; }; }; }; - commands: { - get( - args?: RestArguments, - ): Promise; - post( - args: RestArguments, - ): Promise; - put( - args?: RestArguments, - ): Promise; - ( - id: string, - ): { - get(args?: RestArguments): Promise; - patch( - args: RestArguments, - ): Promise; - delete(args?: RestArguments): Promise; - }; + }; + commands: { + get( + args?: RestArguments, + ): Promise; + post( + args: RestArguments, + ): Promise; + put( + args?: RestArguments, + ): Promise; + ( + id: string, + ): { + get(args?: RestArguments): Promise; + patch( + args: RestArguments, + ): Promise; + delete(args?: RestArguments): Promise; }; - 'role-connections': { - metadata: { - get(args?: RestArguments): Promise; - put( - args: RestArguments, - ): Promise; - }; + }; + 'role-connections': { + metadata: { + get(args?: RestArguments): Promise; + put( + args: RestArguments, + ): Promise; }; }; }; diff --git a/src/api/Routes/channels.ts b/src/api/Routes/channels.ts index 7c14c7e..ad8a86a 100644 --- a/src/api/Routes/channels.ts +++ b/src/api/Routes/channels.ts @@ -66,18 +66,14 @@ export interface ChannelRoutes { ): Promise; //. delete(args?: RestArguments): Promise; - users: { - ( - id: '@me', - ): { - threads: { - archived: { - private: { - //. - get( - args?: RestArguments, - ): Promise; - }; + users: (id: '@me') => { + threads: { + archived: { + private: { + //. + get( + args?: RestArguments, + ): Promise; }; }; }; @@ -131,17 +127,13 @@ export interface ChannelRoutes { }; }; }; - recipients: { - ( - id: string, - ): { - //. - put( - args?: RestArguments, - ): Promise; - //. - delete(args?: RestArguments): Promise; - }; + recipients: (id: string) => { + //. + put( + args?: RestArguments, + ): Promise; + //. + delete(args?: RestArguments): Promise; }; pins: { //. @@ -161,17 +153,13 @@ export interface ChannelRoutes { args: RestArguments, ): Promise; }; - permissions: { - ( - id: string, - ): { - //. - put( - args?: RestArguments, - ): Promise; - //. - delete(args?: RestArguments): Promise; - }; + permissions: (id: string) => { + //. + put( + args?: RestArguments, + ): Promise; + //. + delete(args?: RestArguments): Promise; }; invites: { //. diff --git a/src/api/Routes/interactions.ts b/src/api/Routes/interactions.ts index 026aa38..bf0aba8 100644 --- a/src/api/Routes/interactions.ts +++ b/src/api/Routes/interactions.ts @@ -3,17 +3,9 @@ import type { RestArguments } from '../api'; import type { ProxyRequestMethod } from '../Router'; export interface InteractionRoutes { - interactions: { - ( - id: string, - ): { - ( - token: string, - ): { - callback: { - post(args: RestArguments): Promise; - }; - }; + interactions: (id: string) => (token: string) => { + callback: { + post(args: RestArguments): Promise; }; }; } diff --git a/src/api/Routes/webhooks.ts b/src/api/Routes/webhooks.ts index 91746cd..bb29d96 100644 --- a/src/api/Routes/webhooks.ts +++ b/src/api/Routes/webhooks.ts @@ -65,16 +65,12 @@ export interface WebhookRoutes { >, ): Promise; }; - messages: { - ( - id: string | '@original', - ): { - get(args?: RestArguments): Promise; - patch( - args: RestArguments, - ): Promise; - delete(args?: RestArguments): Promise; - }; + messages: (id: string | '@original') => { + get(args?: RestArguments): Promise; + patch( + args: RestArguments, + ): Promise; + delete(args?: RestArguments): Promise; }; }; }; diff --git a/src/client/base.ts b/src/client/base.ts index 5826966..6363e86 100644 --- a/src/client/base.ts +++ b/src/client/base.ts @@ -7,37 +7,42 @@ import type { MiddlewareContext } from '../commands/applications/shared'; import { CommandHandler } from '../commands/handler'; import { ChannelShorter, + EmojiShorter, GuildShorter, LogLevels, Logger, + MemberShorter, + MessageShorter, + ReactionShorter, + RoleShorter, + TemplateShorter, UsersShorter, + WebhookShorter, filterSplit, magicImport, type LocaleString, type MakeRequired, } from '../common'; -import { MemberShorter } from '../common/shorters/members'; -import { MessageShorter } from '../common/shorters/messages'; -import { RoleShorter } from '../common/shorters/roles'; -import { TemplateShorter } from '../common/shorters/templates'; -import { WebhookShorter } from '../common/shorters/webhook'; + import type { DeepPartial, IntentStrings, OmitInsert } from '../common/types/util'; import { ComponentHandler } from '../components/handler'; import { LangsHandler } from '../langs/handler'; -import type { ChatInputCommandInteraction, MessageCommandInteraction, UserCommandInteraction } from '../structures'; +import type { ChatInputCommandInteraction, Message, MessageCommandInteraction, UserCommandInteraction } from '../structures'; export class BaseClient { rest!: ApiHandler; cache!: Cache; - users = new UsersShorter(this).users; - channels = new ChannelShorter(this).channels; - guilds = new GuildShorter(this).guilds; - messages = new MessageShorter(this).messages; - members = new MemberShorter(this).members; - webhooks = new WebhookShorter(this).webhooks; - templates = new TemplateShorter(this).templates; - roles = new RoleShorter(this).roles; + users = new UsersShorter(this); + channels = new ChannelShorter(this); + guilds = new GuildShorter(this); + messages = new MessageShorter(this); + members = new MemberShorter(this); + webhooks = new WebhookShorter(this); + templates = new TemplateShorter(this); + roles = new RoleShorter(this); + reactions = new ReactionShorter(this); + emojis = new EmojiShorter(this); debugger?: Logger; @@ -240,7 +245,8 @@ export interface BaseClientOptions { interaction: | ChatInputCommandInteraction | UserCommandInteraction - | MessageCommandInteraction, + | MessageCommandInteraction + | Message ) => {}; globalMiddlewares?: readonly (keyof RegisteredMiddlewares)[]; } diff --git a/src/client/onmessagecreate.ts b/src/client/onmessagecreate.ts index fc335a3..3a2f85a 100644 --- a/src/client/onmessagecreate.ts +++ b/src/client/onmessagecreate.ts @@ -44,15 +44,15 @@ function getCommandFromContent( const command = groupName || subcommandName ? (parent.options?.find(opt => { - if (opt instanceof SubCommand) { - if (groupName) { - if (opt.group !== groupName) return false; - } - if (opt.group && !groupName) return false; - return subcommandName === opt.name; + if (opt instanceof SubCommand) { + if (groupName) { + if (opt.group !== groupName) return false; } - return false; - }) as SubCommand) + if (opt.group && !groupName) return false; + return subcommandName === opt.name; + } + return false; + }) as SubCommand) : parent; return { @@ -97,6 +97,8 @@ export async function onMessageCreate( const { options, errors } = await parseOptions(self, command, rawMessage, args, resolved); const optionsResolver = new OptionResolver(self, options, parent as Command, message.guildId, resolved); const context = new CommandContext(self, message, optionsResolver, shardId, command); + const extendContext = self.options?.context?.(message) ?? {}; + Object.assign(context, extendContext); try { if (command.botPermissions && message.guildId) { const meMember = await self.cache.members?.get(self.botId, message.guildId); diff --git a/src/common/index.ts b/src/common/index.ts index 61108be..d064cf0 100644 --- a/src/common/index.ts +++ b/src/common/index.ts @@ -5,8 +5,15 @@ export * from 'discord-api-types/v10'; export * from './it/colors'; export * from './it/logger'; export * from './shorters/channels'; +export * from './shorters/emojis'; export * from './shorters/guilds'; +export * from './shorters/members'; +export * from './shorters/messages'; +export * from './shorters/reactions'; +export * from './shorters/roles'; +export * from './shorters/templates'; export * from './shorters/users'; +export * from './shorters/webhook'; export * from './types/options'; export * from './types/resolvables'; export * from './types/util'; diff --git a/src/common/it/utils.ts b/src/common/it/utils.ts index 3343186..ed57b7b 100644 --- a/src/common/it/utils.ts +++ b/src/common/it/utils.ts @@ -250,6 +250,7 @@ export async function magicImport(path: string) { try { return require(path); } catch { + // biome-ignore lint/security/noGlobalEval: modules import broke return eval('((path) => import(`file:///${path}`))')(path.split('\\').join('\\\\')); } } @@ -263,6 +264,7 @@ export function fakePromise>( } { if (value instanceof Promise) return value as any; return { + // biome-ignore lint/suspicious/noThenProperty: magic then: callback => callback(value as Awaited), }; } diff --git a/src/common/shorters/channels.ts b/src/common/shorters/channels.ts index 630aadf..e031b86 100644 --- a/src/common/shorters/channels.ts +++ b/src/common/shorters/channels.ts @@ -5,180 +5,158 @@ import { PermissionsBitField } from '../../structures/extra/Permissions'; import { BaseShorter } from './base'; export class ChannelShorter extends BaseShorter { - get channels() { + /** + * Fetches a channel by its ID. + * @param id The ID of the channel to fetch. + * @param force Whether to force fetching the channel from the API even if it exists in the cache. + * @returns A Promise that resolves to the fetched channel. + */ + async fetch(id: string, force?: boolean): Promise { + let channel; + if (!force) { + channel = await this.client.cache.channels?.get(id); + if (channel) return channel; + } + + channel = await this.client.proxy.channels(id).get(); + await this.client.cache.channels?.patch(id, undefined, channel); + return channelFrom(channel, this.client); + } + + /** + * Deletes a channel by its ID. + * @param id The ID of the channel to delete. + * @param optional Optional parameters for the deletion. + * @returns A Promise that resolves to the deleted channel. + */ + async delete(id: string, optional: ChannelShorterOptionalParams = { guildId: '@me' }): Promise { + const res = await this.client.proxy.channels(id).delete({ reason: optional.reason }); + await this.client.cache.channels?.removeIfNI(BaseChannel.__intent__(optional.guildId!), res.id, optional.guildId!); + return channelFrom(res, this.client); + } + + /** + * Edits a channel by its ID. + * @param id The ID of the channel to edit. + * @param body The updated channel data. + * @param optional Optional parameters for the editing. + * @returns A Promise that resolves to the edited channel. + */ + async edit( + id: string, + body: RESTPatchAPIChannelJSONBody, + optional: ChannelShorterOptionalParams = { guildId: '@me' }, + ): Promise { + const res = await this.client.proxy.channels(id).patch({ body, reason: optional.reason }); + await this.client.cache.channels?.setIfNI( + BaseChannel.__intent__(optional.guildId!), + res.id, + optional.guildId!, + res, + ); + if (body.permission_overwrites && 'permission_overwrites' in res) + await this.client.cache.overwrites?.setIfNI( + BaseChannel.__intent__(optional.guildId!), + res.id, + optional.guildId!, + res.permission_overwrites, + ); + return channelFrom(res, this.client); + } + + /** + * Sends a typing indicator to the channel. + * @param id The ID of the channel. + * @returns A Promise that resolves when the typing indicator is successfully sent. + */ + async typing(id: string): Promise { + await this.client.proxy.channels(id).typing.post(); + } + + async pins(channelId: string): Promise { + const messages = await this.client.proxy.channels(channelId).pins.get(); + return messages.map(message => new Message(this.client, message)); + } + + /** + * Pins a message in the channel. + * @param messageId The ID of the message to pin. + * @param channelId The ID of the channel. + * @param reason The reason for pinning the message. + * @returns A Promise that resolves when the message is successfully pinned. + */ + setPin(messageId: string, channelId: string, reason?: string) { + return this.client.proxy.channels(channelId).pins(messageId).put({ reason }); + } + + /** + * Unpins a message in the channel. + * @param messageId The ID of the message to unpin. + * @param channelId The ID of the channel. + * @param reason The reason for unpinning the message. + * @returns A Promise that resolves when the message is successfully unpinned. + */ + deletePin(messageId: string, channelId: string, reason?: string) { + return this.client.proxy.channels(channelId).pins(messageId).delete({ reason }); + } + + async memberPermissions(channelId: string, member: GuildMember, checkAdmin = true): Promise { + const permissions = await member.fetchPermissions(); + + if (checkAdmin && permissions.has(PermissionFlagsBits.Administrator)) { + return new PermissionsBitField(PermissionsBitField.All); + } + + const overwrites = await this.overwritesFor(channelId, member); + + permissions.remove(overwrites.everyone?.deny.bits ?? 0n); + permissions.add(overwrites.everyone?.allow.bits ?? 0n); + permissions.remove(overwrites.roles.length > 0 ? overwrites.roles.map(role => role.deny.bits) : 0n); + permissions.add(overwrites.roles.length > 0 ? overwrites.roles.map(role => role.allow.bits) : 0n); + permissions.remove(overwrites.member?.deny.bits ?? 0n); + permissions.add(overwrites.member?.allow.bits ?? 0n); + return permissions; + } + + async overwritesFor(channelId: string, member: GuildMember) { + const roleOverwrites = []; + let memberOverwrites; + let everyoneOverwrites; + + const channelOverwrites = (await this.client.cache.overwrites?.get(channelId)) ?? []; + + for (const overwrite of channelOverwrites) { + if (overwrite.id === member.guildId) { + everyoneOverwrites = overwrite; + } else if (member.roles.values.includes(overwrite.id)) { + roleOverwrites.push(overwrite); + } else if (overwrite.id === member.id) { + memberOverwrites = overwrite; + } + } + return { - /** - * Fetches a channel by its ID. - * @param id The ID of the channel to fetch. - * @param force Whether to force fetching the channel from the API even if it exists in the cache. - * @returns A Promise that resolves to the fetched channel. - */ - fetch: async (id: string, force?: boolean): Promise => { - let channel; - if (!force) { - channel = await this.client.cache.channels?.get(id); - if (channel) return channel; - } - - channel = await this.client.proxy.channels(id).get(); - await this.client.cache.channels?.patch(id, undefined, channel); - return channelFrom(channel, this.client); - }, - - /** - * Deletes a channel by its ID. - * @param id The ID of the channel to delete. - * @param optional Optional parameters for the deletion. - * @returns A Promise that resolves to the deleted channel. - */ - delete: async (id: string, optional: ChannelShorterOptionalParams = { guildId: '@me' }) => { - const res = await this.client.proxy.channels(id).delete({ reason: optional.reason }); - await this.client.cache.channels?.removeIfNI( - BaseChannel.__intent__(optional.guildId!), - res.id, - optional.guildId!, - ); - return channelFrom(res, this.client); - }, - - /** - * Edits a channel by its ID. - * @param id The ID of the channel to edit. - * @param body The updated channel data. - * @param optional Optional parameters for the editing. - * @returns A Promise that resolves to the edited channel. - */ - edit: async ( - id: string, - body: RESTPatchAPIChannelJSONBody, - optional: ChannelShorterOptionalParams = { guildId: '@me' }, - ) => { - const res = await this.client.proxy.channels(id).patch({ body, reason: optional.reason }); - await this.client.cache.channels?.setIfNI( - BaseChannel.__intent__(optional.guildId!), - res.id, - optional.guildId!, - res, - ); - if (body.permission_overwrites && 'permission_overwrites' in res) - await this.client.cache.overwrites?.setIfNI( - BaseChannel.__intent__(optional.guildId!), - res.id, - optional.guildId!, - res.permission_overwrites, - ); - return channelFrom(res, this.client); - }, - - /** - * Sends a typing indicator to the channel. - * @param id The ID of the channel. - * @returns A Promise that resolves when the typing indicator is successfully sent. - */ - typing: (id: string) => this.client.proxy.channels(id).typing.post(), - - /** - * Provides access to pinned messages in the channel. - */ - pins: this.pins, - overwrites: this.overwrites, + everyone: everyoneOverwrites, + roles: roleOverwrites, + member: memberOverwrites, }; } - get pins() { - return { - /** - * Fetches pinned messages in the channel. - * @param channelId The ID of the channel. - * @returns A Promise that resolves to an array of pinned messages. - */ - fetch: (channelId: string) => - this.client.proxy - .channels(channelId) - .pins.get() - .then(messages => messages.map(message => new Message(this.client, message))), + async rolePermissions(channelId: string, role: GuildRole, checkAdmin = true): Promise { + if (checkAdmin && role.permissions.has(PermissionFlagsBits.Administrator)) { + return new PermissionsBitField(PermissionsBitField.All); + } + const channelOverwrites = (await this.client.cache.overwrites?.get(channelId)) ?? []; - /** - * Pins a message in the channel. - * @param messageId The ID of the message to pin. - * @param channelId The ID of the channel. - * @param reason The reason for pinning the message. - * @returns A Promise that resolves when the message is successfully pinned. - */ - set: (messageId: string, channelId: string, reason?: string) => - this.client.proxy.channels(channelId).pins(messageId).put({ reason }), + const everyoneOverwrites = channelOverwrites.find(x => x.id === role.guildId); + const roleOverwrites = channelOverwrites.find(x => x.id === role.id); + const permissions = new PermissionsBitField(role.permissions.bits); - /** - * Unpins a message in the channel. - * @param messageId The ID of the message to unpin. - * @param channelId The ID of the channel. - * @param reason The reason for unpinning the message. - * @returns A Promise that resolves when the message is successfully unpinned. - */ - delete: (messageId: string, channelId: string, reason?: string) => - this.client.proxy.channels(channelId).pins(messageId).delete({ reason }), - }; - } - - get overwrites() { - return { - memberPermissions: async (channelId: string, member: GuildMember, checkAdmin = true) => { - const permissions = await member.fetchPermissions(); - - if (checkAdmin && permissions.has(PermissionFlagsBits.Administrator)) { - return new PermissionsBitField(PermissionsBitField.All); - } - - const overwrites = await this.overwrites.overwritesFor(channelId, member); - - permissions.remove(overwrites.everyone?.deny.bits ?? 0n); - permissions.add(overwrites.everyone?.allow.bits ?? 0n); - permissions.remove(overwrites.roles.length > 0 ? overwrites.roles.map(role => role.deny.bits) : 0n); - permissions.add(overwrites.roles.length > 0 ? overwrites.roles.map(role => role.allow.bits) : 0n); - permissions.remove(overwrites.member?.deny.bits ?? 0n); - permissions.add(overwrites.member?.allow.bits ?? 0n); - return permissions; - }, - overwritesFor: async (channelId: string, member: GuildMember) => { - const roleOverwrites = []; - let memberOverwrites; - let everyoneOverwrites; - - const channelOverwrites = (await this.client.cache.overwrites?.get(channelId)) ?? []; - - for (const overwrite of channelOverwrites) { - if (overwrite.id === member.guildId) { - everyoneOverwrites = overwrite; - } else if (member.roles.values.includes(overwrite.id)) { - roleOverwrites.push(overwrite); - } else if (overwrite.id === member.id) { - memberOverwrites = overwrite; - } - } - - return { - everyone: everyoneOverwrites, - roles: roleOverwrites, - member: memberOverwrites, - }; - }, - rolePermissions: async (channelId: string, role: GuildRole, checkAdmin = true) => { - if (checkAdmin && role.permissions.has(PermissionFlagsBits.Administrator)) { - return new PermissionsBitField(PermissionsBitField.All); - } - const channelOverwrites = (await this.client.cache.overwrites?.get(channelId)) ?? []; - - const everyoneOverwrites = channelOverwrites.find(x => x.id === role.guildId); - const roleOverwrites = channelOverwrites.find(x => x.id === role.id); - const permissions = new PermissionsBitField(role.permissions.bits); - - permissions.remove(everyoneOverwrites?.deny.bits ?? 0n); - permissions.add(everyoneOverwrites?.allow.bits ?? 0n); - permissions.remove(roleOverwrites?.deny.bits ?? 0n); - permissions.add(roleOverwrites?.allow.bits ?? 0n); - return permissions; - }, - }; + permissions.remove(everyoneOverwrites?.deny.bits ?? 0n); + permissions.add(everyoneOverwrites?.allow.bits ?? 0n); + permissions.remove(roleOverwrites?.deny.bits ?? 0n); + permissions.add(roleOverwrites?.allow.bits ?? 0n); + return permissions; } } diff --git a/src/common/shorters/emojis.ts b/src/common/shorters/emojis.ts new file mode 100644 index 0000000..863ea81 --- /dev/null +++ b/src/common/shorters/emojis.ts @@ -0,0 +1,86 @@ +import type { APIEmoji, RESTPatchAPIGuildEmojiJSONBody, RESTPostAPIGuildEmojiJSONBody } from 'discord-api-types/v10'; +import { GuildEmoji } from '../..'; +import { resolveImage } from '../../builders'; +import type { ImageResolvable } from '../types/resolvables'; +import type { OmitInsert } from '../types/util'; +import { BaseShorter } from './base'; + +export class EmojiShorter extends BaseShorter { + /** + * Retrieves a list of emojis in the guild. + * @param guildId The ID of the guild. + * @param force Whether to force fetching emojis from the API even if they exist in the cache. + * @returns A Promise that resolves to an array of emojis. + */ + async list(guildId: string, force = false) { + let emojis; + if (!force) { + emojis = (await this.client.cache.emojis?.values(guildId)) ?? []; + if (emojis.length) { + return emojis; + } + } + emojis = await this.client.proxy.guilds(guildId).emojis.get(); + await this.client.cache.emojis?.set( + emojis.map<[string, APIEmoji]>(x => [x.id!, x]), + guildId, + ); + return emojis.map(m => new GuildEmoji(this.client, m, guildId)); + } + + /** + * Creates a new emoji in the guild. + * @param guildId The ID of the guild. + * @param body The data for creating the emoji. + * @returns A Promise that resolves to the created emoji. + */ + async create(guildId: string, body: OmitInsert) { + const bodyResolved = { ...body, image: await resolveImage(body.image) }; + const emoji = await this.client.proxy.guilds(guildId).emojis.post({ + body: bodyResolved, + }); + await this.client.cache.channels?.setIfNI('GuildEmojisAndStickers', emoji.id!, guildId, emoji); + } + + /** + * Fetches an emoji by its ID. + * @param guildId The ID of the guild. + * @param emojiId The ID of the emoji to fetch. + * @param force Whether to force fetching the emoji from the API even if it exists in the cache. + * @returns A Promise that resolves to the fetched emoji. + */ + async fetch(guildId: string, emojiId: string, force = false) { + let emoji; + if (!force) { + emoji = await this.client.cache.emojis?.get(emojiId); + if (emoji) return emoji; + } + emoji = await this.client.proxy.guilds(guildId).emojis(emojiId).get(); + return new GuildEmoji(this.client, emoji, guildId); + } + + /** + * Deletes an emoji from the guild. + * @param guildId The ID of the guild. + * @param emojiId The ID of the emoji to delete. + * @param reason The reason for deleting the emoji. + */ + async delete(guildId: string, emojiId: string, reason?: string) { + await this.client.proxy.guilds(guildId).emojis(emojiId).delete({ reason }); + await this.client.cache.channels?.removeIfNI('GuildEmojisAndStickers', emojiId, guildId); + } + + /** + * Edits an emoji in the guild. + * @param guildId The ID of the guild. + * @param emojiId The ID of the emoji to edit. + * @param body The data to update the emoji with. + * @param reason The reason for editing the emoji. + * @returns A Promise that resolves to the edited emoji. + */ + async edit(guildId: string, emojiId: string, body: RESTPatchAPIGuildEmojiJSONBody, reason?: string) { + const emoji = await this.client.proxy.guilds(guildId).emojis(emojiId).patch({ body, reason }); + await this.client.cache.channels?.setIfNI('GuildEmojisAndStickers', emoji.id!, guildId, emoji); + return new GuildEmoji(this.client, emoji, guildId); + } +} diff --git a/src/common/shorters/guilds.ts b/src/common/shorters/guilds.ts index 352229a..c0a7e86 100644 --- a/src/common/shorters/guilds.ts +++ b/src/common/shorters/guilds.ts @@ -1,23 +1,21 @@ import type { + APIChannel, GuildWidgetStyle, RESTGetAPICurrentUserGuildsQuery, RESTPatchAPIAutoModerationRuleJSONBody, RESTPatchAPIChannelJSONBody, RESTPatchAPIGuildChannelPositionsJSONBody, - RESTPatchAPIGuildEmojiJSONBody, RESTPatchAPIGuildStickerJSONBody, RESTPostAPIAutoModerationRuleJSONBody, RESTPostAPIGuildChannelJSONBody, - RESTPostAPIGuildEmojiJSONBody, RESTPostAPIGuildsJSONBody, } from 'discord-api-types/v10'; -import type { ImageResolvable, ObjectToLower, OmitInsert } from '..'; -import { resolveFiles, resolveImage } from '../../builders'; +import type { ObjectToLower } from '..'; +import { resolveFiles } from '../../builders'; import { AnonymousGuild, BaseChannel, Guild, - GuildEmoji, GuildMember, Sticker, type CreateStickerBodyRequest, @@ -27,163 +25,67 @@ import { BaseShorter } from './base'; export class GuildShorter extends BaseShorter { /** - * Provides access to guild-related functionality. + * Creates a new guild. + * @param body The data for creating the guild. + * @returns A Promise that resolves to the created guild. */ - get guilds() { - return { - /** - * Creates a new guild. - * @param body The data for creating the guild. - * @returns A Promise that resolves to the created guild. - */ - create: async (body: RESTPostAPIGuildsJSONBody) => { - const guild = await this.client.proxy.guilds.post({ body }); - await this.client.cache.guilds?.setIfNI('Guilds', guild.id, guild); - return new Guild<'api'>(this.client, guild); - }, - - /** - * Fetches a guild by its ID. - * @param id The ID of the guild to fetch. - * @param force Whether to force fetching the guild from the API even if it exists in the cache. - * @returns A Promise that resolves to the fetched guild. - */ - fetch: async (id: string, force = false) => { - if (!force) { - const guild = await this.client.cache.guilds?.get(id); - if (guild) return guild; - } - - const data = await this.client.proxy.guilds(id).get(); - await this.client.cache.guilds?.patch(id, data); - return (await this.client.cache.guilds?.get(id)) ?? new Guild<'api'>(this.client, data); - }, - - /** - * Generates the widget URL for the guild. - * @param id The ID of the guild. - * @param style The style of the widget. - * @returns The generated widget URL. - */ - widgetURL: (id: string, style?: GuildWidgetStyle) => { - const query = new URLSearchParams(); - if (style) { - query.append('style', style); - } - - return this.client.proxy.guilds(id).widget.get({ query }); - }, - list: (query?: RESTGetAPICurrentUserGuildsQuery) => { - return this.client.proxy - .users('@me') - .guilds.get({ query }) - .then(guilds => guilds.map(guild => new AnonymousGuild(this.client, { ...guild, splash: null }))); - }, - fetchSelf: async (id: string) => { - const self = await this.client.proxy.guilds(id).members(this.client.botId).get(); - await this.client.cache.members?.patch(self.user!.id, id, self); - return new GuildMember(this.client, self, self.user!, id); - }, - leave: (id: string) => { - return this.client.proxy - .users('@me') - .guilds(id) - .delete() - .then(() => this.client.cache.guilds?.removeIfNI('Guilds', id)); - }, - channels: this.channels, - moderation: this.moderation, - stickers: this.stickers, - emojis: this.emojis, - }; + async create(body: RESTPostAPIGuildsJSONBody): Promise> { + const guild = await this.client.proxy.guilds.post({ body }); + await this.client.cache.guilds?.setIfNI('Guilds', guild.id, guild); + return new Guild<'api'>(this.client, guild); } /** - * Provides access to emoji-related functionality in a guild. + * Fetches a guild by its ID. + * @param id The ID of the guild to fetch. + * @param force Whether to force fetching the guild from the API even if it exists in the cache. + * @returns A Promise that resolves to the fetched guild. */ - get emojis() { - return { - /** - * Retrieves a list of emojis in the guild. - * @param guildId The ID of the guild. - * @param force Whether to force fetching emojis from the API even if they exist in the cache. - * @returns A Promise that resolves to an array of emojis. - */ - list: async (guildId: string, force = false) => { - let emojis; - if (!force) { - emojis = (await this.client.cache.emojis?.values(guildId)) ?? []; - if (emojis.length) { - return emojis; - } - } - emojis = await this.client.proxy.guilds(guildId).emojis.get(); - await this.client.cache.emojis?.set( - emojis.map(x => [x.id!, x]), - guildId, - ); - return emojis.map(m => new GuildEmoji(this.client, m, guildId)); - }, + async fetch(id: string, force = false) { + if (!force) { + const guild = await this.client.cache.guilds?.get(id); + if (guild) return guild; + } - /** - * Creates a new emoji in the guild. - * @param guildId The ID of the guild. - * @param body The data for creating the emoji. - * @returns A Promise that resolves to the created emoji. - */ - create: async ( - guildId: string, - body: OmitInsert, - ) => { - const bodyResolved = { ...body, image: await resolveImage(body.image) }; - const emoji = await this.client.proxy.guilds(guildId).emojis.post({ - body: bodyResolved, - }); - await this.client.cache.channels?.setIfNI('GuildEmojisAndStickers', emoji.id!, guildId, emoji); - }, + const data = await this.client.proxy.guilds(id).get(); + await this.client.cache.guilds?.patch(id, data); + return (await this.client.cache.guilds?.get(id)) ?? new Guild<'api'>(this.client, data); + } - /** - * Fetches an emoji by its ID. - * @param guildId The ID of the guild. - * @param emojiId The ID of the emoji to fetch. - * @param force Whether to force fetching the emoji from the API even if it exists in the cache. - * @returns A Promise that resolves to the fetched emoji. - */ - fetch: async (guildId: string, emojiId: string, force = false) => { - let emoji; - if (!force) { - emoji = await this.client.cache.emojis?.get(emojiId); - if (emoji) return emoji; - } - emoji = await this.client.proxy.guilds(guildId).emojis(emojiId).get(); - return new GuildEmoji(this.client, emoji, guildId); - }, + /** + * Generates the widget URL for the guild. + * @param id The ID of the guild. + * @param style The style of the widget. + * @returns The generated widget URL. + */ + widgetURL(id: string, style?: GuildWidgetStyle) { + const query = new URLSearchParams(); + if (style) { + query.append('style', style); + } - /** - * Deletes an emoji from the guild. - * @param guildId The ID of the guild. - * @param emojiId The ID of the emoji to delete. - * @param reason The reason for deleting the emoji. - */ - delete: async (guildId: string, emojiId: string, reason?: string) => { - await this.client.proxy.guilds(guildId).emojis(emojiId).delete({ reason }); - await this.client.cache.channels?.removeIfNI('GuildEmojisAndStickers', emojiId, guildId); - }, + return this.client.proxy.guilds(id).widget.get({ query }); + } - /** - * Edits an emoji in the guild. - * @param guildId The ID of the guild. - * @param emojiId The ID of the emoji to edit. - * @param body The data to update the emoji with. - * @param reason The reason for editing the emoji. - * @returns A Promise that resolves to the edited emoji. - */ - edit: async (guildId: string, emojiId: string, body: RESTPatchAPIGuildEmojiJSONBody, reason?: string) => { - const emoji = await this.client.proxy.guilds(guildId).emojis(emojiId).patch({ body, reason }); - await this.client.cache.channels?.setIfNI('GuildEmojisAndStickers', emoji.id!, guildId, emoji); - return new GuildEmoji(this.client, emoji, guildId); - }, - }; + list(query?: RESTGetAPICurrentUserGuildsQuery) { + return this.client.proxy + .users('@me') + .guilds.get({ query }) + .then(guilds => guilds.map(guild => new AnonymousGuild(this.client, { ...guild, splash: null }))); + } + + async fetchSelf(id: string) { + const self = await this.client.proxy.guilds(id).members(this.client.botId).get(); + await this.client.cache.members?.patch(self.user!.id, id, self); + return new GuildMember(this.client, self, self.user!, id); + } + + leave(id: string) { + return this.client.proxy + .users('@me') + .guilds(id) + .delete() + .then(() => this.client.cache.guilds?.removeIfNI('Guilds', id)); } /** @@ -207,7 +109,7 @@ export class GuildShorter extends BaseShorter { } channels = await this.client.proxy.guilds(guildId).channels.get(); await this.client.cache.channels?.set( - channels.map(x => [x.id, x]), + channels.map<[string, APIChannel]>(x => [x.id, x]), guildId, ); return channels.map(m => channelFrom(m, this.client)); diff --git a/src/common/shorters/members.ts b/src/common/shorters/members.ts index 4996368..68dde13 100644 --- a/src/common/shorters/members.ts +++ b/src/common/shorters/members.ts @@ -13,188 +13,172 @@ import { BaseShorter } from './base'; export class MemberShorter extends BaseShorter { /** - * Provides access to member-related functionality in a guild. + * Resolves a member in the guild based on the provided GuildMemberResolvable. + * @param guildId The ID of the guild. + * @param resolve The GuildMemberResolvable to resolve. + * @returns A Promise that resolves to the resolved member. */ - get members() { - return { - /** - * Resolves a member in the guild based on the provided GuildMemberResolvable. - * @param guildId The ID of the guild. - * @param resolve The GuildMemberResolvable to resolve. - * @returns A Promise that resolves to the resolved member. - */ - resolve: async (guildId: string, resolve: GuildMemberResolvable) => { - if (typeof resolve === 'string') { - const match: { id?: string } | undefined = resolve.match(FormattingPatterns.User)?.groups; - if (match?.id) { - return this.members.fetch(guildId, match.id); - } - if (resolve.match(/\d{17,20}/)) { - return this.members.fetch(guildId, resolve); - } - return this.members.search(guildId, { query: resolve, limit: 1 }).then(x => x[0]); - } - if (resolve.id) { - return this.client.members.fetch(guildId, resolve.id); - } - return resolve.displayName - ? this.members.search(guildId, { query: resolve.displayName, limit: 1 }).then(x => x[0]) - : undefined; - }, - - /** - * Searches for members in the guild based on the provided query. - * @param guildId The ID of the guild. - * @param query The query parameters for searching members. - * @returns A Promise that resolves to an array of matched members. - */ - search: async (guildId: string, query?: RESTGetAPIGuildMembersSearchQuery) => { - const members = await this.client.proxy.guilds(guildId).members.search.get({ - query, - }); - await this.client.cache.members?.set( - members.map(x => [x.user!.id, x]), - guildId, - ); - return members.map(m => new GuildMember(this.client, m, m.user!, guildId)); - }, - - /** - * Unbans a member from the guild. - * @param guildId The ID of the guild. - * @param memberId The ID of the member to unban. - * @param body The request body for unbanning the member. - * @param reason The reason for unbanning the member. - */ - unban: async (guildId: string, memberId: string, body?: RESTPutAPIGuildBanJSONBody, reason?: string) => { - await this.client.proxy.guilds(guildId).bans(memberId).delete({ reason, body }); - }, - - /** - * Bans a member from the guild. - * @param guildId The ID of the guild. - * @param memberId The ID of the member to ban. - * @param body The request body for banning the member. - * @param reason The reason for banning the member. - */ - ban: async (guildId: string, memberId: string, body?: RESTPutAPIGuildBanJSONBody, reason?: string) => { - await this.client.proxy.guilds(guildId).bans(memberId).put({ reason, body }); - await this.client.cache.members?.removeIfNI('GuildBans', memberId, guildId); - }, - - /** - * Kicks a member from the guild. - * @param guildId The ID of the guild. - * @param memberId The ID of the member to kick. - * @param reason The reason for kicking the member. - */ - kick: async (guildId: string, memberId: string, reason?: string) => { - await this.client.proxy.guilds(guildId).members(memberId).delete({ reason }); - await this.client.cache.members?.removeIfNI('GuildMembers', memberId, guildId); - }, - - /** - * Edits a member in the guild. - * @param guildId The ID of the guild. - * @param memberId The ID of the member to edit. - * @param body The data to update the member with. - * @param reason The reason for editing the member. - * @returns A Promise that resolves to the edited member. - */ - edit: async (guildId: string, memberId: string, body: RESTPatchAPIGuildMemberJSONBody, reason?: string) => { - const member = await this.client.proxy.guilds(guildId).members(memberId).patch({ body, reason }); - await this.client.cache.members?.setIfNI('GuildMembers', memberId, guildId, member); - return new GuildMember(this.client, member, member.user!, guildId); - }, - - /** - * Adds a member to the guild. - * @param guildId The ID of the guild. - * @param memberId The ID of the member to add. - * @param body The request body for adding the member. - * @returns A Promise that resolves to the added member. - */ - add: async (guildId: string, memberId: string, body: RESTPutAPIGuildMemberJSONBody) => { - const member = await this.client.proxy.guilds(guildId).members(memberId).put({ - body, - }); - - // Thanks dapi-types, fixed - if (!member) { - return; - } - - await this.client.cache.members?.setIfNI('GuildMembers', member.user!.id, guildId, member); - - return new GuildMember(this.client, member, member.user!, guildId); - }, - - /** - * Fetches a member from the guild. - * @param guildId The ID of the guild. - * @param memberId The ID of the member to fetch. - * @param force Whether to force fetching the member from the API even if it exists in the cache. - * @returns A Promise that resolves to the fetched member. - */ - fetch: async (guildId: string, memberId: string, force = false) => { - let member; - if (!force) { - member = await this.client.cache.members?.get(memberId, guildId); - if (member) return member; - } - - member = await this.client.proxy.guilds(guildId).members(memberId).get(); - await this.client.cache.members?.set(member.user!.id, guildId, member); - return new GuildMember(this.client, member, member.user!, guildId); - }, - - /** - * Lists members in the guild based on the provided query. - * @param guildId The ID of the guild. - * @param query The query parameters for listing members. - * @param force Whether to force listing members from the API even if they exist in the cache. - * @returns A Promise that resolves to an array of listed members. - */ - list: async (guildId: string, query?: RESTGetAPIGuildMembersQuery, force = false) => { - let members; - if (!force) { - members = (await this.client.cache.members?.values(guildId)) ?? []; - if (members.length) return members; - } - members = await this.client.proxy.guilds(guildId).members.get({ - query, - }); - await this.client.cache.members?.set(members.map(x => [x.user!.id, x]) as [string, APIGuildMember][], guildId); - return members.map(m => new GuildMember(this.client, m, m.user!, guildId)); - }, - /** - * Provides methods to add and remove roles from a guild member. - */ - roles: this.roles, - }; + async resolve(guildId: string, resolve: GuildMemberResolvable) { + if (typeof resolve === 'string') { + const match: { id?: string } | undefined = resolve.match(FormattingPatterns.User)?.groups; + if (match?.id) { + return this.fetch(guildId, match.id); + } + if (resolve.match(/\d{17,20}/)) { + return this.fetch(guildId, resolve); + } + return this.search(guildId, { query: resolve, limit: 1 }).then(x => x[0]); + } + if (resolve.id) { + return this.client.members.fetch(guildId, resolve.id); + } + return resolve.displayName + ? this.search(guildId, { query: resolve.displayName, limit: 1 }).then(x => x[0]) + : undefined; } - get roles() { - return { - /** - * Adds a role to a guild member. - * @param guildId The ID of the guild. - * @param memberId The ID of the member to add the role to. - * @param id The ID of the role to add. - */ - add: async (guildId: string, memberId: string, id: string) => { - await this.client.proxy.guilds(guildId).members(memberId).roles(id).put({}); - }, + /** + * Searches for members in the guild based on the provided query. + * @param guildId The ID of the guild. + * @param query The query parameters for searching members. + * @returns A Promise that resolves to an array of matched members. + */ + async search(guildId: string, query?: RESTGetAPIGuildMembersSearchQuery) { + const members = await this.client.proxy.guilds(guildId).members.search.get({ + query, + }); + await this.client.cache.members?.set( + members.map(x => [x.user!.id, x]), + guildId, + ); + return members.map(m => new GuildMember(this.client, m, m.user!, guildId)); + } - /** - * Removes a role from a guild member. - * @param guildId The ID of the guild. - * @param memberId The ID of the member to remove the role from. - * @param id The ID of the role to remove. - */ - remove: async (guildId: string, memberId: string, id: string) => { - await this.client.proxy.guilds(guildId).members(memberId).roles(id).delete(); - }, - }; + /** + * Unbans a member from the guild. + * @param guildId The ID of the guild. + * @param memberId The ID of the member to unban. + * @param body The request body for unbanning the member. + * @param reason The reason for unbanning the member. + */ + async unban(guildId: string, memberId: string, body?: RESTPutAPIGuildBanJSONBody, reason?: string) { + await this.client.proxy.guilds(guildId).bans(memberId).delete({ reason, body }); + } + + /** + * Bans a member from the guild. + * @param guildId The ID of the guild. + * @param memberId The ID of the member to ban. + * @param body The request body for banning the member. + * @param reason The reason for banning the member. + */ + async ban(guildId: string, memberId: string, body?: RESTPutAPIGuildBanJSONBody, reason?: string) { + await this.client.proxy.guilds(guildId).bans(memberId).put({ reason, body }); + await this.client.cache.members?.removeIfNI('GuildBans', memberId, guildId); + } + + /** + * Kicks a member from the guild. + * @param guildId The ID of the guild. + * @param memberId The ID of the member to kick. + * @param reason The reason for kicking the member. + */ + async kick(guildId: string, memberId: string, reason?: string) { + await this.client.proxy.guilds(guildId).members(memberId).delete({ reason }); + await this.client.cache.members?.removeIfNI('GuildMembers', memberId, guildId); + } + + /** + * Edits a member in the guild. + * @param guildId The ID of the guild. + * @param memberId The ID of the member to edit. + * @param body The data to update the member with. + * @param reason The reason for editing the member. + * @returns A Promise that resolves to the edited member. + */ + async edit(guildId: string, memberId: string, body: RESTPatchAPIGuildMemberJSONBody, reason?: string) { + const member = await this.client.proxy.guilds(guildId).members(memberId).patch({ body, reason }); + await this.client.cache.members?.setIfNI('GuildMembers', memberId, guildId, member); + return new GuildMember(this.client, member, member.user!, guildId); + } + + /** + * Adds a member to the guild. + * @param guildId The ID of the guild. + * @param memberId The ID of the member to add. + * @param body The request body for adding the member. + * @returns A Promise that resolves to the added member. + */ + async add(guildId: string, memberId: string, body: RESTPutAPIGuildMemberJSONBody) { + const member = await this.client.proxy.guilds(guildId).members(memberId).put({ + body, + }); + + // Thanks dapi-types, fixed + if (!member) { + return; + } + + await this.client.cache.members?.setIfNI('GuildMembers', member.user!.id, guildId, member); + + return new GuildMember(this.client, member, member.user!, guildId); + } + + /** + * Fetches a member from the guild. + * @param guildId The ID of the guild. + * @param memberId The ID of the member to fetch. + * @param force Whether to force fetching the member from the API even if it exists in the cache. + * @returns A Promise that resolves to the fetched member. + */ + async fetch(guildId: string, memberId: string, force = false) { + let member; + if (!force) { + member = await this.client.cache.members?.get(memberId, guildId); + if (member) return member; + } + + member = await this.client.proxy.guilds(guildId).members(memberId).get(); + await this.client.cache.members?.set(member.user!.id, guildId, member); + return new GuildMember(this.client, member, member.user!, guildId); + } + + /** + * Lists members in the guild based on the provided query. + * @param guildId The ID of the guild. + * @param query The query parameters for listing members. + * @param force Whether to force listing members from the API even if they exist in the cache. + * @returns A Promise that resolves to an array of listed members. + */ + async list(guildId: string, query?: RESTGetAPIGuildMembersQuery, force = false) { + let members; + if (!force) { + members = (await this.client.cache.members?.values(guildId)) ?? []; + if (members.length) return members; + } + members = await this.client.proxy.guilds(guildId).members.get({ + query, + }); + await this.client.cache.members?.set(members.map(x => [x.user!.id, x]) as [string, APIGuildMember][], guildId); + return members.map(m => new GuildMember(this.client, m, m.user!, guildId)); + } + + /** + * Adds a role to a guild member. + * @param guildId The ID of the guild. + * @param memberId The ID of the member to add the role to. + * @param id The ID of the role to add. + */ + addRole(guildId: string, memberId: string, id: string) { + this.client.proxy.guilds(guildId).members(memberId).roles(id).put({}); + } + /** + * Removes a role from a guild member. + * @param guildId The ID of the guild. + * @param memberId The ID of the member to remove the role from. + * @param id The ID of the role to remove. + */ + removeRole(guildId: string, memberId: string, id: string) { + return this.client.proxy.guilds(guildId).members(memberId).roles(id).delete(); } } diff --git a/src/common/shorters/messages.ts b/src/common/shorters/messages.ts index 92b86fb..7ffe2bf 100644 --- a/src/common/shorters/messages.ts +++ b/src/common/shorters/messages.ts @@ -1,134 +1,80 @@ import type { - RESTGetAPIChannelMessageReactionUsersQuery, RESTPatchAPIChannelMessageJSONBody, RESTPostAPIChannelMessageJSONBody, + RESTPostAPIChannelMessagesThreadsJSONBody, } from 'discord-api-types/v10'; import { resolveFiles } from '../../builders'; -import { Message, MessagesMethods, User } from '../../structures'; -import { encodeEmoji, resolveEmoji } from '../../structures/extra/functions'; -import type { EmojiResolvable } from '../types/resolvables'; +import { Message, MessagesMethods, ThreadChannel } from '../../structures'; import type { MessageCreateBodyRequest, MessageUpdateBodyRequest } from '../types/write'; import { BaseShorter } from './base'; export class MessageShorter extends BaseShorter { - get messages() { - return { - write: async (channelId: string, { files, ...body }: MessageCreateBodyRequest) => { - const parsedFiles = files ? await resolveFiles(files) : []; + async write(channelId: string, { files, ...body }: MessageCreateBodyRequest) { + const parsedFiles = files ? await resolveFiles(files) : []; - const transformedBody = MessagesMethods.transformMessageBody(body); - return this.client.proxy - .channels(channelId) - .messages.post({ - body: transformedBody, - files: parsedFiles, - }) - .then(message => { - return new Message(this.client, message); - }); - }, - edit: async (messageId: string, channelId: string, { files, ...body }: MessageUpdateBodyRequest) => { - const parsedFiles = files ? await resolveFiles(files) : []; - return this.client.proxy - .channels(channelId) - .messages(messageId) - .patch({ - body: MessagesMethods.transformMessageBody(body), - files: parsedFiles, - }) - .then(message => { - return new Message(this.client, message); - }); - }, - crosspost: (messageId: string, channelId: string, reason?: string) => { - return this.client.proxy - .channels(channelId) - .messages(messageId) - .crosspost.post({ reason }) - .then(m => new Message(this.client, m)); - }, - delete: (messageId: string, channelId: string, reason?: string) => { - return this.client.proxy - .channels(channelId) - .messages(messageId) - .delete({ reason }) - .then(() => { - return this.client.components.onMessageDelete(messageId); - }); - }, - fetch: async (messageId: string, channelId: string) => { - return this.client.proxy - .channels(channelId) - .messages(messageId) - .get() - .then(x => new Message(this.client, x)); - }, - purge: (messages: string[], channelId: string, reason?: string) => { - return this.client.proxy.channels(channelId).messages['bulk-delete'].post({ body: { messages }, reason }); - }, - reactions: this.reactions, - }; + const transformedBody = MessagesMethods.transformMessageBody(body); + return this.client.proxy + .channels(channelId) + .messages.post({ + body: transformedBody, + files: parsedFiles, + }) + .then(message => { + return new Message(this.client, message); + }); + } + async edit(messageId: string, channelId: string, { files, ...body }: MessageUpdateBodyRequest) { + const parsedFiles = files ? await resolveFiles(files) : []; + return this.client.proxy + .channels(channelId) + .messages(messageId) + .patch({ + body: MessagesMethods.transformMessageBody(body), + files: parsedFiles, + }) + .then(message => { + return new Message(this.client, message); + }); } - get reactions() { - return { - add: async (messageId: string, channelId: string, emoji: EmojiResolvable) => { - const rawEmoji = await resolveEmoji(emoji, this.client.cache); + crosspost(messageId: string, channelId: string, reason?: string) { + return this.client.proxy + .channels(channelId) + .messages(messageId) + .crosspost.post({ reason }) + .then(m => new Message(this.client, m)); + } + delete(messageId: string, channelId: string, reason?: string) { + return this.client.proxy + .channels(channelId) + .messages(messageId) + .delete({ reason }) + .then(() => { + return this.client.components.onMessageDelete(messageId); + }); + } + fetch(messageId: string, channelId: string) { + return this.client.proxy + .channels(channelId) + .messages(messageId) + .get() + .then(x => new Message(this.client, x)); + } + purge(messages: string[], channelId: string, reason?: string) { + return this.client.proxy.channels(channelId).messages['bulk-delete'].post({ body: { messages }, reason }); + } - if (!rawEmoji) { - throw new Error('Emoji no resolvable'); - } + thread( + channelId: string, + messageId: string, + options: RESTPostAPIChannelMessagesThreadsJSONBody & { reason?: string }, + ) { + const { reason, ...body } = options; - return this.client.proxy - .channels(channelId) - .messages(messageId) - .reactions(encodeEmoji(rawEmoji))('@me') - .put({}); - }, - delete: async (messageId: string, channelId: string, emoji: EmojiResolvable, userId = '@me') => { - const rawEmoji = await resolveEmoji(emoji, this.client.cache); - - if (!rawEmoji) { - throw new Error('Emoji no resolvable'); - } - - return this.client.proxy - .channels(channelId) - .messages(messageId) - .reactions(encodeEmoji(rawEmoji))(userId) - .delete(); - }, - fetch: async ( - messageId: string, - channelId: string, - emoji: EmojiResolvable, - query?: RESTGetAPIChannelMessageReactionUsersQuery, - ) => { - const rawEmoji = await resolveEmoji(emoji, this.client.cache); - - if (!rawEmoji) { - throw new Error('Emoji no resolvable'); - } - - return this.client.proxy - .channels(channelId) - .messages(messageId) - .reactions(encodeEmoji(rawEmoji)) - .get({ query }) - .then(u => u.map(user => new User(this.client, user))); - }, - purge: async (messageId: string, channelId: string, emoji?: EmojiResolvable) => { - if (!emoji) { - return this.client.proxy.channels(channelId).messages(messageId).reactions.delete(); - } - const rawEmoji = await resolveEmoji(emoji, this.client.cache); - - if (!rawEmoji) { - throw new Error('Emoji no resolvable'); - } - - return this.client.proxy.channels(channelId).messages(messageId).reactions(encodeEmoji(rawEmoji)).delete(); - }, - }; + return this.client.proxy + .channels(channelId) + .messages(messageId) + .threads.post({ body, reason }) + .then(x => new ThreadChannel(this.client, x)); } } diff --git a/src/common/shorters/reactions.ts b/src/common/shorters/reactions.ts new file mode 100644 index 0000000..ed27557 --- /dev/null +++ b/src/common/shorters/reactions.ts @@ -0,0 +1,60 @@ +import type { RESTGetAPIChannelMessageReactionUsersQuery } from 'discord-api-types/v10'; +import { User } from '../../structures'; +import { encodeEmoji, resolveEmoji } from '../../structures/extra/functions'; +import type { EmojiResolvable } from '../types/resolvables'; +import { BaseShorter } from './base'; + +export class ReactionShorter extends BaseShorter { + async add(messageId: string, channelId: string, emoji: EmojiResolvable): Promise { + const rawEmoji = await resolveEmoji(emoji, this.client.cache); + + if (!rawEmoji) { + throw new Error('Emoji no resolvable'); + } + + return this.client.proxy.channels(channelId).messages(messageId).reactions(encodeEmoji(rawEmoji))('@me').put({}); + } + + async delete(messageId: string, channelId: string, emoji: EmojiResolvable, userId = '@me'): Promise { + const rawEmoji = await resolveEmoji(emoji, this.client.cache); + + if (!rawEmoji) { + throw new Error('Emoji no resolvable'); + } + + return this.client.proxy.channels(channelId).messages(messageId).reactions(encodeEmoji(rawEmoji))(userId).delete(); + } + + async fetch( + messageId: string, + channelId: string, + emoji: EmojiResolvable, + query?: RESTGetAPIChannelMessageReactionUsersQuery, + ): Promise { + const rawEmoji = await resolveEmoji(emoji, this.client.cache); + + if (!rawEmoji) { + throw new Error('Emoji no resolvable'); + } + + return this.client.proxy + .channels(channelId) + .messages(messageId) + .reactions(encodeEmoji(rawEmoji)) + .get({ query }) + .then(u => u.map(user => new User(this.client, user))); + } + + async purge(messageId: string, channelId: string, emoji?: EmojiResolvable): Promise { + if (!emoji) { + return this.client.proxy.channels(channelId).messages(messageId).reactions.delete(); + } + const rawEmoji = await resolveEmoji(emoji, this.client.cache); + + if (!rawEmoji) { + throw new Error('Emoji no resolvable'); + } + + return this.client.proxy.channels(channelId).messages(messageId).reactions(encodeEmoji(rawEmoji)).delete(); + } +} diff --git a/src/common/shorters/roles.ts b/src/common/shorters/roles.ts index b8cb031..caf8656 100644 --- a/src/common/shorters/roles.ts +++ b/src/common/shorters/roles.ts @@ -8,54 +8,89 @@ import { GuildRole } from '../../structures'; import { BaseShorter } from './base'; export class RoleShorter extends BaseShorter { - get roles() { - return { - create: (guildId: string, body: RESTPostAPIGuildRoleJSONBody, reason?: string) => - this.client.proxy - .guilds(guildId) - .roles.post({ body, reason }) - .then(res => this.client.cache.roles?.setIfNI('Guilds', res.id, guildId, res)), - list: async (guildId: string, force = false) => { - let roles: APIRole[] = []; - if (!force) { - const cachedRoles = (await this.client.cache.roles?.values(guildId)) ?? []; - if (cachedRoles.length) { - return cachedRoles; - } - } - roles = await this.client.proxy.guilds(guildId).roles.get(); - await this.client.cache.roles?.set( - roles.map(r => [r.id, r]), - guildId, - ); - return roles.map(r => new GuildRole(this.client, r, guildId)); - }, - edit: (guildId: string, roleId: string, body: RESTPatchAPIGuildRoleJSONBody, reason?: string) => { - return this.client.proxy - .guilds(guildId) - .roles(roleId) - .patch({ body, reason }) - .then(res => this.client.cache.roles?.setIfNI('Guilds', roleId, guildId, res)); - }, - delete: (guildId: string, roleId: string, reason?: string) => { - return this.client.proxy - .guilds(guildId) - .roles(roleId) - .delete({ reason }) - .then(() => this.client.cache.roles?.removeIfNI('Guilds', roleId, guildId)); - }, - editPositions: async (guildId: string, body: RESTPatchAPIGuildRolePositionsJSONBody) => { - const roles = await this.client.proxy.guilds(guildId).roles.patch({ - body, - }); - if (!this.client.cache.hasRolesIntent) { - await this.client.cache.roles?.set( - roles.map(x => [x.id, x]), - guildId, - ); - } - return roles.map(x => new GuildRole(this.client, x, guildId)); - }, - }; + /** + * Creates a new role in the guild. + * @param guildId The ID of the guild. + * @param body The data for creating the role. + * @param reason The reason for creating the role. + * @returns A Promise that resolves when the role is created. + */ + create(guildId: string, body: RESTPostAPIGuildRoleJSONBody, reason?: string) { + return this.client.proxy + .guilds(guildId) + .roles.post({ body, reason }) + .then(res => this.client.cache.roles?.setIfNI('Guilds', res.id, guildId, res)); + } + + /** + * Retrieves a list of roles in the guild. + * @param guildId The ID of the guild. + * @param force Whether to force fetching roles from the API even if they exist in the cache. + * @returns A Promise that resolves to an array of roles. + */ + async list(guildId: string, force = false) { + let roles: APIRole[] = []; + if (!force) { + const cachedRoles = (await this.client.cache.roles?.values(guildId)) ?? []; + if (cachedRoles.length) { + return cachedRoles; + } + } + roles = await this.client.proxy.guilds(guildId).roles.get(); + await this.client.cache.roles?.set( + roles.map<[string, APIRole]>(r => [r.id, r]), + guildId, + ); + return roles.map(r => new GuildRole(this.client, r, guildId)); + } + + /** + * Edits a role in the guild. + * @param guildId The ID of the guild. + * @param roleId The ID of the role to edit. + * @param body The data to update the role with. + * @param reason The reason for editing the role. + * @returns A Promise that resolves when the role is edited. + */ + edit(guildId: string, roleId: string, body: RESTPatchAPIGuildRoleJSONBody, reason?: string) { + return this.client.proxy + .guilds(guildId) + .roles(roleId) + .patch({ body, reason }) + .then(res => this.client.cache.roles?.setIfNI('Guilds', roleId, guildId, res)); + } + + /** + * Deletes a role from the guild. + * @param guildId The ID of the guild. + * @param roleId The ID of the role to delete. + * @param reason The reason for deleting the role. + * @returns A Promise that resolves when the role is deleted. + */ + delete(guildId: string, roleId: string, reason?: string) { + return this.client.proxy + .guilds(guildId) + .roles(roleId) + .delete({ reason }) + .then(() => this.client.cache.roles?.removeIfNI('Guilds', roleId, guildId)); + } + + /** + * Edits the positions of roles in the guild. + * @param guildId The ID of the guild. + * @param body The data to update the positions of roles with. + * @returns A Promise that resolves to an array of edited roles. + */ + async editPositions(guildId: string, body: RESTPatchAPIGuildRolePositionsJSONBody) { + const roles = await this.client.proxy.guilds(guildId).roles.patch({ + body, + }); + if (!this.client.cache.hasRolesIntent) { + await this.client.cache.roles?.set( + roles.map(x => [x.id, x]), + guildId, + ); + } + return roles.map(x => new GuildRole(this.client, x, guildId)); } } diff --git a/src/common/shorters/templates.ts b/src/common/shorters/templates.ts index aef018b..8702249 100644 --- a/src/common/shorters/templates.ts +++ b/src/common/shorters/templates.ts @@ -2,26 +2,27 @@ import type { RESTPatchAPIGuildTemplateJSONBody, RESTPostAPIGuildTemplatesJSONBo import { BaseShorter } from './base'; export class TemplateShorter extends BaseShorter { - get templates() { - return { - fetch: (code: string) => { - return this.client.proxy.guilds.templates(code).get(); - }, - list: (guildId: string) => { - return this.client.proxy.guilds(guildId).templates.get(); - }, - create: (guildId: string, body: RESTPostAPIGuildTemplatesJSONBody) => { - return this.client.proxy.guilds(guildId).templates.post({ body }); - }, - sync: (guildId: string, code: string) => { - return this.client.proxy.guilds(guildId).templates(code).put({}); - }, - edit: (guildId: string, code: string, body: RESTPatchAPIGuildTemplateJSONBody) => { - return this.client.proxy.guilds(guildId).templates(code).patch({ body }); - }, - delete: (guildId: string, code: string) => { - return this.client.proxy.guilds(guildId).templates(code).delete(); - }, - }; + fetch(code: string) { + return this.client.proxy.guilds.templates(code).get(); + } + + list(guildId: string) { + return this.client.proxy.guilds(guildId).templates.get(); + } + + create(guildId: string, body: RESTPostAPIGuildTemplatesJSONBody) { + return this.client.proxy.guilds(guildId).templates.post({ body }); + } + + sync(guildId: string, code: string) { + return this.client.proxy.guilds(guildId).templates(code).put({}); + } + + edit(guildId: string, code: string, body: RESTPatchAPIGuildTemplateJSONBody) { + return this.client.proxy.guilds(guildId).templates(code).patch({ body }); + } + + delete(guildId: string, code: string) { + return this.client.proxy.guilds(guildId).templates(code).delete(); } } diff --git a/src/common/shorters/users.ts b/src/common/shorters/users.ts index b0788b6..9a3ea7b 100644 --- a/src/common/shorters/users.ts +++ b/src/common/shorters/users.ts @@ -3,6 +3,39 @@ import type { MessageCreateBodyRequest } from '../types/write'; import { BaseShorter } from './base'; export class UsersShorter extends BaseShorter { + async createDM(userId: string, force = false) { + if (!force) { + const dm = await this.client.cache.channels?.get(userId); + if (dm) return dm as DMChannel; + } + const data = await this.client.proxy.users('@me').channels.post({ + body: { recipient_id: userId }, + }); + await this.client.cache.channels?.set(userId, '@me', data); + return new DMChannel(this.client, data); + } + + async deleteDM(userId: string, reason?: string) { + const res = await this.client.proxy.channels(userId).delete({ reason }); + await this.client.cache.channels?.removeIfNI(BaseChannel.__intent__('@me'), res.id, '@me'); + return new DMChannel(this.client, res); + } + + async fetch(userId: string, force = false) { + if (!force) { + const user = await this.client.cache.users?.get(userId); + if (user) return user; + } + + const data = await this.client.proxy.users(userId).get(); + await this.client.cache.users?.patch(userId, data); + return new User(this.client, data); + } + + async write(userId: string, body: MessageCreateBodyRequest) { + return (await this.client.users.createDM(userId)).messages.write(body); + } + get users() { return { createDM: async (userId: string, force = false) => { diff --git a/src/common/shorters/webhook.ts b/src/common/shorters/webhook.ts index 680a4ab..cb4b3bb 100644 --- a/src/common/shorters/webhook.ts +++ b/src/common/shorters/webhook.ts @@ -5,82 +5,128 @@ import type { } from '..'; import { resolveFiles } from '../../builders'; import { - type MessageWebhookMethodEditParams, - type MessageWebhookMethodWriteParams, MessagesMethods, Webhook, WebhookMessage, + type MessageWebhookMethodEditParams, + type MessageWebhookMethodWriteParams, } from '../../structures'; import { BaseShorter } from './base'; export class WebhookShorter extends BaseShorter { - get webhooks() { - return { - delete: (webhookId: string, { token, reason }: WebhookShorterOptionalParams) => { - if (token) { - return this.client.proxy.webhooks(webhookId)(token).delete({ reason, auth: false }); - } - return this.client.proxy.webhooks(webhookId).delete({ reason }); - }, - edit: ( - webhookId: string, - body: RESTPatchAPIWebhookWithTokenJSONBody | RESTPatchAPIWebhookJSONBody, - { token, reason }: WebhookShorterOptionalParams, - ) => { - if (token) { - return this.client.proxy.webhooks(webhookId)(token).patch({ body, reason, auth: false }); - } - return this.client.proxy.webhooks(webhookId).patch({ body, reason }); - }, - fetch: async (webhookId: string, token?: string) => { - let webhook; - if (token) { - webhook = await this.client.proxy.webhooks(webhookId)(token).get({ auth: false }); - } else { - webhook = await this.client.proxy.webhooks(webhookId).get(); - } - return new Webhook(this.client, webhook); - }, - messages: this.messages, - }; + /** + * Deletes a webhook. + * @param webhookId The ID of the webhook. + * @param options The optional parameters including token and reason. + * @returns A Promise that resolves when the webhook is deleted. + */ + delete(webhookId: string, options: WebhookShorterOptionalParams) { + if (options.token) { + return this.client.proxy.webhooks(webhookId)(options.token).delete({ reason: options.reason, auth: false }); + } + return this.client.proxy.webhooks(webhookId).delete({ reason: options.reason }); } - get messages() { - return { - write: async (webhookId: string, token: string, { body: data, ...payload }: MessageWebhookMethodWriteParams) => { - const { files, ...body } = data; - const transformedBody = MessagesMethods.transformMessageBody(body); - const parsedFiles = files ? await resolveFiles(files) : []; - return this.client.proxy - .webhooks(webhookId)(token) - .post({ ...payload, files: parsedFiles, body: transformedBody }) - .then(m => (m?.id ? new WebhookMessage(this.client, m, webhookId, token) : null)); - }, - edit: async ( - webhookId: string, - token: string, - { messageId, body: data, ...json }: MessageWebhookMethodEditParams, - ) => { - const { files, ...body } = data; - const transformedBody = MessagesMethods.transformMessageBody(body); - const parsedFiles = files ? await resolveFiles(files) : []; - return this.client.proxy - .webhooks(webhookId)(token) - .messages(messageId) - .patch({ ...json, auth: false, files: parsedFiles, body: transformedBody }) - .then(m => new WebhookMessage(this.client, m, webhookId, token)); - }, - delete: async (webhookId: string, token: string, messageId: string, reason?: string) => { - return this.client.proxy.webhooks(webhookId)(token).messages(messageId).delete({ reason }); - }, - fetch: async (webhookId: string, token: string, messageId: string, threadId?: string) => { - const message = await this.client.proxy - .webhooks(webhookId)(token) - .messages(messageId) - .get({ auth: false, query: { threadId } }); - return message ? new WebhookMessage(this.client, message, webhookId, token) : undefined; - }, - }; + /** + * Edits a webhook. + * @param webhookId The ID of the webhook. + * @param body The data to update the webhook with. + * @param options The optional parameters including token and reason. + * @returns A Promise that resolves when the webhook is edited. + */ + edit( + webhookId: string, + body: RESTPatchAPIWebhookWithTokenJSONBody | RESTPatchAPIWebhookJSONBody, + options: WebhookShorterOptionalParams, + ) { + if (options.token) { + return this.client.proxy.webhooks(webhookId)(options.token).patch({ body, reason: options.reason, auth: false }); + } + return this.client.proxy.webhooks(webhookId).patch({ body, reason: options.reason }); + } + + /** + * Fetches a webhook. + * @param webhookId The ID of the webhook. + * @param token The token of the webhook (optional). + * @returns A Promise that resolves to the fetched webhook. + */ + async fetch(webhookId: string, token?: string) { + let webhook; + if (token) { + webhook = await this.client.proxy.webhooks(webhookId)(token).get({ auth: false }); + } else { + webhook = await this.client.proxy.webhooks(webhookId).get(); + } + return new Webhook(this.client, webhook); + } + + /** + * Writes a message using the webhook. + * @param webhookId The ID of the webhook. + * @param token The token of the webhook. + * @param data The data for writing the message. + * @returns A Promise that resolves to the written message. + */ + async writeMessage(webhookId: string, token: string, { body: data, ...payload }: MessageWebhookMethodWriteParams) { + const { files, ...body } = data; + const transformedBody = MessagesMethods.transformMessageBody(body); + const parsedFiles = files ? await resolveFiles(files) : []; + return this.client.proxy + .webhooks(webhookId)(token) + .post({ ...payload, files: parsedFiles, body: transformedBody }) + .then(m => (m?.id ? new WebhookMessage(this.client, m, webhookId, token) : null)); + } + + /** + * Edits a message sent by the webhook. + * @param webhookId The ID of the webhook. + * @param token The token of the webhook. + * @param messageId The ID of the message to edit. + * @param data The data for editing the message. + * @returns A Promise that resolves to the edited message. + */ + async editMessage( + webhookId: string, + token: string, + { messageId, body: data, ...json }: MessageWebhookMethodEditParams, + ) { + const { files, ...body } = data; + const transformedBody = MessagesMethods.transformMessageBody(body); + const parsedFiles = files ? await resolveFiles(files) : []; + return this.client.proxy + .webhooks(webhookId)(token) + .messages(messageId) + .patch({ ...json, auth: false, files: parsedFiles, body: transformedBody }) + .then(m => new WebhookMessage(this.client, m, webhookId, token)); + } + + /** + * Deletes a message sent by the webhook. + * @param webhookId The ID of the webhook. + * @param token The token of the webhook. + * @param messageId The ID of the message to delete. + * @param reason The reason for deleting the message. + * @returns A Promise that resolves when the message is deleted. + */ + deleteMessage(webhookId: string, token: string, messageId: string, reason?: string) { + return this.client.proxy.webhooks(webhookId)(token).messages(messageId).delete({ reason }); + } + + /** + * Fetches a message sent by the webhook. + * @param webhookId The ID of the webhook. + * @param token The token of the webhook. + * @param messageId The ID of the message to fetch. + * @param threadId The ID of the thread the message belongs to. + * @returns A Promise that resolves to the fetched message, or undefined if not found. + */ + async fetchMessage(webhookId: string, token: string, messageId: string, threadId?: string) { + const message = await this.client.proxy + .webhooks(webhookId)(token) + .messages(messageId) + .get({ auth: false, query: { threadId } }); + return message ? new WebhookMessage(this.client, message, webhookId, token) : undefined; } } diff --git a/src/index.ts b/src/index.ts index 77ac638..2caf22a 100644 --- a/src/index.ts +++ b/src/index.ts @@ -1,7 +1,7 @@ import type { InternalRuntimeConfig, InternalRuntimeConfigHTTP, RuntimeConfig, RuntimeConfigHTTP } from './client/base'; import { GatewayIntentBits } from './common'; import type { ClientNameEvents, EventContext } from './events'; -import type { ChatInputCommandInteraction, MessageCommandInteraction, UserCommandInteraction } from './structures'; +import type { ChatInputCommandInteraction, Message, MessageCommandInteraction, UserCommandInteraction } from './structures'; export { Logger, PermissionFlagsBits, PermissionStrings, Watcher } from './common'; // @@ -95,7 +95,7 @@ export const config = { * }); */ export function extendContext( - cb: (interaction: ChatInputCommandInteraction | UserCommandInteraction | MessageCommandInteraction) => T, + cb: (interaction: ChatInputCommandInteraction | UserCommandInteraction | MessageCommandInteraction | Message) => T, ) { return cb; } diff --git a/src/structures/GuildEmoji.ts b/src/structures/GuildEmoji.ts index 773db08..70924b5 100644 --- a/src/structures/GuildEmoji.ts +++ b/src/structures/GuildEmoji.ts @@ -2,7 +2,7 @@ import type { BaseImageURLOptions } from '../api'; import type { BaseClient } from '../client/base'; import type { APIEmoji, - GuildShorter, + EmojiShorter, MethodContext, ObjectToLower, RESTPatchAPIChannelJSONBody, @@ -27,15 +27,15 @@ export class GuildEmoji extends DiscordBase { } edit(body: RESTPatchAPIChannelJSONBody, reason?: string) { - return this.client.guilds.emojis.edit(this.guildId, this.id, body, reason); + return this.client.emojis.edit(this.guildId, this.id, body, reason); } delete(reason?: string) { - return this.client.guilds.emojis.delete(this.guildId, this.id, reason); + return this.client.emojis.delete(this.guildId, this.id, reason); } fetch(force = false) { - return this.client.guilds.emojis.fetch(this.guildId, this.id, force); + return this.client.emojis.fetch(this.guildId, this.id, force); } url(options?: BaseImageURLOptions) { @@ -57,10 +57,10 @@ export class GuildEmoji extends DiscordBase { static methods({ client, guildId }: MethodContext<{ guildId: string }>) { return { edit: (emojiId: string, body: RESTPatchAPIGuildEmojiJSONBody, reason?: string) => - client.guilds.emojis.edit(guildId, emojiId, body, reason), - create: (body: Parameters[1]) => client.guilds.emojis.create(guildId, body), - fetch: (emojiId: string, force = false) => client.guilds.emojis.fetch(guildId, emojiId, force), - list: (force = false) => client.guilds.emojis.list(guildId, force), + client.emojis.edit(guildId, emojiId, body, reason), + create: (body: Parameters[1]) => client.emojis.create(guildId, body), + fetch: (emojiId: string, force = false) => client.emojis.fetch(guildId, emojiId, force), + list: (force = false) => client.emojis.list(guildId, force), }; } } diff --git a/src/structures/GuildMember.ts b/src/structures/GuildMember.ts index fa820f3..059753e 100644 --- a/src/structures/GuildMember.ts +++ b/src/structures/GuildMember.ts @@ -96,8 +96,8 @@ export class BaseGuildMember extends DiscordBase { get roles() { return { values: Object.freeze(this._roles), - add: (id: string) => this.client.members.roles.add(this.guildId, this.id, id), - remove: (id: string) => this.client.members.roles.remove(this.guildId, this.id, id), + add: (id: string) => this.client.members.addRole(this.guildId, this.id, id), + remove: (id: string) => this.client.members.removeRole(this.guildId, this.id, id), permissions: async () => new PermissionsBitField( ((await this.cache.roles?.bulk(this.roles.values as string[])) ?? []) diff --git a/src/structures/Interaction.ts b/src/structures/Interaction.ts index bacf7b7..127b7f6 100644 --- a/src/structures/Interaction.ts +++ b/src/structures/Interaction.ts @@ -326,7 +326,7 @@ export class Interaction< Type extends APIInteraction = APIInteraction, > extends BaseInteraction { fetchMessage(messageId: string) { - return this.client.webhooks.messages.fetch(this.applicationId, this.token, messageId); + return this.client.webhooks.fetchMessage(this.applicationId, this.token, messageId); } fetchResponse() { diff --git a/src/structures/Message.ts b/src/structures/Message.ts index e3265ed..dcea30e 100644 --- a/src/structures/Message.ts +++ b/src/structures/Message.ts @@ -64,7 +64,7 @@ export class BaseMessage extends DiscordBase { } react(emoji: EmojiResolvable) { - return this.client.messages.reactions.add(this.id, this.channelId, emoji); + return this.client.reactions.add(this.id, this.channelId, emoji); } private patch(data: MessageData) { @@ -170,14 +170,14 @@ export class WebhookMessage extends BaseMessage { } edit(body: EditMessageWebhook) { - return this.client.webhooks.messages.edit(this.webhookId, this.webhookToken, { ...body, messageId: this.id }); + return this.client.webhooks.editMessage(this.webhookId, this.webhookToken, { ...body, messageId: this.id }); } write(body: WriteMessageWebhook) { - return this.client.webhooks.messages.write(this.webhookId, this.webhookToken, body); + return this.client.webhooks.writeMessage(this.webhookId, this.webhookToken, body); } delete(reason?: string) { - return this.client.webhooks.messages.delete(this.webhookId, this.webhookToken, this.id, reason); + return this.client.webhooks.deleteMessage(this.webhookId, this.webhookToken, this.id, reason); } } diff --git a/src/structures/Webhook.ts b/src/structures/Webhook.ts index 54f1c07..44e7ea8 100644 --- a/src/structures/Webhook.ts +++ b/src/structures/Webhook.ts @@ -71,11 +71,10 @@ export class Webhook extends DiscordBase { static messages({ client, webhookId, webhookToken }: MethodContext<{ webhookId: string; webhookToken: string }>) { return { write: (payload: MessageWebhookMethodWriteParams) => - client.webhooks.messages.write(webhookId, webhookToken, payload), - edit: (payload: MessageWebhookMethodEditParams) => - client.webhooks.messages.edit(webhookId, webhookToken, payload), + client.webhooks.writeMessage(webhookId, webhookToken, payload), + edit: (payload: MessageWebhookMethodEditParams) => client.webhooks.editMessage(webhookId, webhookToken, payload), delete: (messageId: string, reason?: string) => - client.webhooks.messages.delete(webhookId, webhookToken, messageId, reason), + client.webhooks.deleteMessage(webhookId, webhookToken, messageId, reason), }; } diff --git a/src/structures/channels.ts b/src/structures/channels.ts index c4dd4c7..fd92bff 100644 --- a/src/structures/channels.ts +++ b/src/structures/channels.ts @@ -176,15 +176,15 @@ export class BaseGuildChannel extends BaseChannel { }; memberPermissions(member: GuildMember, checkAdmin = true) { - return this.client.channels.overwrites.memberPermissions(this.id, member, checkAdmin); + return this.client.channels.memberPermissions(this.id, member, checkAdmin); } rolePermissions(role: GuildRole, checkAdmin = true) { - return this.client.channels.overwrites.rolePermissions(this.id, role, checkAdmin); + return this.client.channels.rolePermissions(this.id, role, checkAdmin); } overwritesFor(member: GuildMember) { - return this.client.channels.overwrites.overwritesFor(this.id, member); + return this.client.channels.overwritesFor(this.id, member); } guild(force = false) { @@ -233,21 +233,20 @@ export class MessagesMethods extends DiscordBase { static reactions(ctx: MethodContext<{ channelId: string }>) { return { - add: (messageId: string, emoji: EmojiResolvable) => - ctx.client.messages.reactions.add(messageId, ctx.channelId, emoji), + add: (messageId: string, emoji: EmojiResolvable) => ctx.client.reactions.add(messageId, ctx.channelId, emoji), delete: (messageId: string, emoji: EmojiResolvable, userId = '@me') => - ctx.client.messages.reactions.delete(messageId, ctx.channelId, emoji, userId), + ctx.client.reactions.delete(messageId, ctx.channelId, emoji, userId), fetch: (messageId: string, emoji: EmojiResolvable, query?: RESTGetAPIChannelMessageReactionUsersQuery) => - ctx.client.messages.reactions.fetch(messageId, ctx.channelId, emoji, query), + ctx.client.reactions.fetch(messageId, ctx.channelId, emoji, query), purge: (messageId: string, emoji?: EmojiResolvable) => - ctx.client.messages.reactions.purge(messageId, ctx.channelId, emoji), + ctx.client.reactions.purge(messageId, ctx.channelId, emoji), }; } static pins(ctx: MethodContext<{ channelId: string }>) { return { - fetch: () => ctx.client.channels.pins.fetch(ctx.channelId), - set: (messageId: string, reason?: string) => ctx.client.channels.pins.set(messageId, ctx.channelId, reason), - delete: (messageId: string, reason?: string) => ctx.client.channels.pins.delete(messageId, ctx.channelId, reason), + fetch: () => ctx.client.channels.pins(ctx.channelId), + set: (messageId: string, reason?: string) => ctx.client.channels.setPin(messageId, ctx.channelId, reason), + delete: (messageId: string, reason?: string) => ctx.client.channels.deletePin(messageId, ctx.channelId, reason), }; } diff --git a/src/websocket/discord/shard.ts b/src/websocket/discord/shard.ts index bac52c3..590cf0c 100644 --- a/src/websocket/discord/shard.ts +++ b/src/websocket/discord/shard.ts @@ -55,7 +55,9 @@ export class Shard { } get latency() { - return this.heart.lastAck && this.heart.lastBeat ? this.heart.lastAck - this.heart.lastBeat : Infinity; + return this.heart.lastAck && this.heart.lastBeat + ? this.heart.lastAck - this.heart.lastBeat + : Number.POSITIVE_INFINITY; } get isOpen() {