diff --git a/packages/discord.js/src/managers/MessageManager.js b/packages/discord.js/src/managers/MessageManager.js index 6642efcac..cab6380a2 100644 --- a/packages/discord.js/src/managers/MessageManager.js +++ b/packages/discord.js/src/managers/MessageManager.js @@ -35,40 +35,79 @@ class MessageManager extends CachedManager { } /** - * The parameters to pass in when requesting previous messages from a channel. `around`, `before` and - * `after` are mutually exclusive. All the parameters are optional. - * @typedef {Object} ChannelLogsQueryOptions - * @property {number} [limit] Number of messages to acquire - * @property {Snowflake} [before] The message's id to get the messages that were posted before it - * @property {Snowflake} [after] The message's id to get the messages that were posted after it - * @property {Snowflake} [around] The message's id to get the messages that were posted around it + * Data that can be resolved to a Message object. This can be: + * * A Message + * * A Snowflake + * @typedef {Message|Snowflake} MessageResolvable */ /** - * Gets a message, or messages, from this channel. + * Options used to fetch a message. + * @typedef {BaseFetchOptions} FetchMessageOptions + * @property {MessageResolvable} [message] The message to fetch + */ + + /** + * Options used to fetch multiple messages. + * @typedef {Object} FetchMessagesOptions + * @property {number} [limit] The maximum number of messages to return + * @property {Snowflake} [before] Consider only messages before this id + * @property {Snowflake} [after] Consider only messages after this id + * @property {Snowflake} [around] Consider only messages around this id + * @property {boolean} [cache] Whether to cache the fetched messages + */ + + /** + * Fetches message(s) from a channel. * The returned Collection does not contain reaction users of the messages if they were not cached. * Those need to be fetched separately in such a case. - * @param {Snowflake|ChannelLogsQueryOptions} [message] The id of the message to fetch, or query parameters. - * @param {BaseFetchOptions} [options] Additional options for this fetch + * @param {MessageResolvable|FetchMessageOptions|FetchMessagesOptions} [options] Options for fetching message(s) * @returns {Promise>} * @example - * // Get message + * // Fetch a message * channel.messages.fetch('99539446449315840') * .then(message => console.log(message.content)) * .catch(console.error); * @example - * // Get messages - * channel.messages.fetch({ limit: 10 }) + * // Fetch a maximum of 10 messages without caching + * channel.messages.fetch({ limit: 10, cache: false }) * .then(messages => console.log(`Received ${messages.size} messages`)) * .catch(console.error); * @example - * // Get messages and filter by user id + * // Fetch a maximum of 10 messages without caching around a message id + * channel.messages.fetch({ limit: 10, cache: false, around: '99539446449315840' }) + * .then(messages => console.log(`Received ${messages.size} messages`)) + * .catch(console.error); + * @example + * // Fetch messages and filter by a user id * channel.messages.fetch() * .then(messages => console.log(`${messages.filter(m => m.author.id === '84484653687267328').size} messages`)) * .catch(console.error); */ - fetch(message, { cache = true, force = false } = {}) { - return typeof message === 'string' ? this._fetchId(message, cache, force) : this._fetchMany(message, cache); + fetch(options) { + if (!options) return this._fetchMany(); + const { message, cache, force } = options; + const resolvedMessage = this.resolveId(message ?? options); + if (resolvedMessage) return this._fetchSingle({ message: resolvedMessage, cache, force }); + return this._fetchMany(options); + } + + async _fetchSingle({ message, cache, force = false }) { + if (!force) { + const existing = this.cache.get(message); + if (existing && !existing.partial) return existing; + } + + const data = await this.client.rest.get(Routes.channelMessage(this.channel.id, message)); + return this._add(data, cache); + } + + async _fetchMany(options = {}) { + const data = await this.client.rest.get(Routes.channelMessages(this.channel.id), { + query: makeURLSearchParams(options), + }); + + return data.reduce((_data, message) => _data.set(message.id, this._add(message, options.cache)), new Collection()); } /** @@ -90,13 +129,6 @@ class MessageManager extends CachedManager { return messages; } - /** - * Data that can be resolved to a Message object. This can be: - * * A Message - * * A Snowflake - * @typedef {Message|Snowflake} MessageResolvable - */ - /** * Resolves a {@link MessageResolvable} to a {@link Message} object. * @method resolve @@ -212,25 +244,6 @@ class MessageManager extends CachedManager { await this.client.rest.delete(Routes.channelMessage(this.channel.id, message)); } - - async _fetchId(messageId, cache, force) { - if (!force) { - const existing = this.cache.get(messageId); - if (existing && !existing.partial) return existing; - } - - const data = await this.client.rest.get(Routes.channelMessage(this.channel.id, messageId)); - return this._add(data, cache); - } - - async _fetchMany(options = {}, cache) { - const data = await this.client.rest.get(Routes.channelMessages(this.channel.id), { - query: makeURLSearchParams(options), - }); - const messages = new Collection(); - for (const message of data) messages.set(message.id, this._add(message, cache)); - return messages; - } } module.exports = MessageManager; diff --git a/packages/discord.js/typings/index.d.ts b/packages/discord.js/typings/index.d.ts index 977cad0b5..801244b0a 100644 --- a/packages/discord.js/typings/index.d.ts +++ b/packages/discord.js/typings/index.d.ts @@ -3207,11 +3207,8 @@ export class MessageManager extends CachedManager; public delete(message: MessageResolvable): Promise; public edit(message: MessageResolvable, options: string | MessagePayload | MessageEditOptions): Promise; - public fetch(message: Snowflake, options?: BaseFetchOptions): Promise; - public fetch( - options?: ChannelLogsQueryOptions, - cacheOptions?: BaseFetchOptions, - ): Promise>; + public fetch(options: MessageResolvable | FetchMessageOptions): Promise; + public fetch(options?: FetchMessagesOptions): Promise>; public fetchPinned(cache?: boolean): Promise>; public react(message: MessageResolvable, emoji: EmojiIdentifierResolvable): Promise; public pin(message: MessageResolvable, reason?: string): Promise; @@ -3736,13 +3733,6 @@ export interface ChannelData { videoQualityMode?: VideoQualityMode | null; } -export interface ChannelLogsQueryOptions { - limit?: number; - before?: Snowflake; - after?: Snowflake; - around?: Snowflake; -} - export type ChannelMention = `<#${Snowflake}>`; export interface ChannelPosition { @@ -4324,6 +4314,18 @@ export interface FetchMembersOptions { force?: boolean; } +export interface FetchMessageOptions extends BaseFetchOptions { + message: MessageResolvable; +} + +export interface FetchMessagesOptions { + limit?: number; + before?: Snowflake; + after?: Snowflake; + around?: Snowflake; + cache?: boolean; +} + export interface FetchReactionUsersOptions { limit?: number; after?: Snowflake; diff --git a/packages/discord.js/typings/index.test-d.ts b/packages/discord.js/typings/index.test-d.ts index 6a909be9e..b9c603f2e 100644 --- a/packages/discord.js/typings/index.test-d.ts +++ b/packages/discord.js/typings/index.test-d.ts @@ -119,6 +119,7 @@ import { MessageActionRowComponentBuilder, GuildBanManager, GuildBan, + MessageManager, } from '.'; import { expectAssignable, expectDeprecated, expectNotAssignable, expectNotType, expectType } from 'tsd'; import { UnsafeButtonBuilder, UnsafeEmbedBuilder, UnsafeSelectMenuBuilder } from '@discordjs/builders'; @@ -1019,6 +1020,22 @@ declare const guildChannelManager: GuildChannelManager; expectType>(guildChannelManager.fetch('0')); } +declare const messageManager: MessageManager; +{ + expectType>(messageManager.fetch('1234567890')); + expectType>(messageManager.fetch({ message: '1234567890' })); + expectType>(messageManager.fetch({ message: '1234567890', cache: true, force: false })); + expectType>>(messageManager.fetch()); + expectType>>(messageManager.fetch({})); + expectType>>( + messageManager.fetch({ limit: 100, before: '1234567890', cache: false }), + ); + // @ts-expect-error + messageManager.fetch({ cache: true, force: false }); + // @ts-expect-error + messageManager.fetch({ message: '1234567890', after: '1234567890', cache: true, force: false }); +} + declare const roleManager: RoleManager; expectType>>(roleManager.fetch()); expectType>>(roleManager.fetch(undefined, {}));