diff --git a/packages/discord.js/src/managers/MessageManager.js b/packages/discord.js/src/managers/MessageManager.js index dcddf2857383..bd38a1a77673 100644 --- a/packages/discord.js/src/managers/MessageManager.js +++ b/packages/discord.js/src/managers/MessageManager.js @@ -1,5 +1,6 @@ 'use strict'; +const process = require('node:process'); const { Collection } = require('@discordjs/collection'); const { makeURLSearchParams } = require('@discordjs/rest'); const { Routes } = require('discord-api-types/v10'); @@ -10,6 +11,8 @@ const MessagePayload = require('../structures/MessagePayload'); const { MakeCacheOverrideSymbol } = require('../util/Symbols'); const { resolvePartialEmoji } = require('../util/Util'); +let deprecationEmittedForFetchPinned = false; + /** * Manages API methods for Messages and holds their cache. * @extends {CachedManager} @@ -116,19 +119,83 @@ class MessageManager extends CachedManager { return data.reduce((_data, message) => _data.set(message.id, this._add(message, options.cache)), new Collection()); } + /** + * Options used to fetch pinned messages. + * + * @typedef {Object} FetchPinnedMessagesOptions + * @property {DateResolvable} [before] Consider only pinned messages before this time + * @property {number} [limit] The maximum number of pinned messages to return + * @property {boolean} [cache] Whether to cache the pinned messages + */ + + /** + * Data returned from fetching pinned messages. + * + * @typedef {Object} FetchPinnedMessagesResponse + * @property {MessagePin[]} items The pinned messages + * @property {boolean} hasMore Whether there are additional pinned messages that require a subsequent call + */ + + /** + * Pinned message data returned from fetching pinned messages. + * + * @typedef {Object} MessagePin + * @property {Date} pinnedAt The time the message was pinned at + * @property {number} pinnedTimestamp The timestamp the message was pinned at + * @property {Message} message The pinned message + */ + /** * Fetches the pinned messages of this channel and returns a collection of them. * The returned Collection does not contain any reaction data of the messages. * Those need to be fetched separately. - * @param {boolean} [cache=true] Whether to cache the message(s) - * @returns {Promise>} + * + * @param {FetchPinnedMessagesOptions} [options={}] Options for fetching pinned messages + * @returns {Promise} * @example * // Get pinned messages - * channel.messages.fetchPinned() - * .then(messages => console.log(`Received ${messages.size} messages`)) + * channel.messages.fetchPins() + * .then(messages => console.log(`Received ${messages.items.length} messages`)) * .catch(console.error); */ + async fetchPins(options = {}) { + const data = await this.client.rest.get(Routes.channelMessagesPins(this.channel.id), { + query: makeURLSearchParams({ + ...options, + before: options.before && new Date(options.before).toISOString(), + }), + }); + + return { + items: data.items.map(item => ({ + pinnedTimestamp: Date.parse(item.pinned_at), + get pinnedAt() { + return new Date(this.pinnedTimestamp); + }, + message: this._add(item.message, options.cache), + })), + hasMore: data.has_more, + }; + } + + /** + * Fetches the pinned messages of this channel and returns a collection of them. + * The returned Collection does not contain any reaction data of the messages. + * Those need to be fetched separately. + * @param {boolean} [cache=true] Whether to cache the message(s) + * @deprecated Use {@link MessageManager#fetchPins} instead. + * @returns {Promise>} + */ async fetchPinned(cache = true) { + if (!deprecationEmittedForFetchPinned) { + process.emitWarning( + 'The MessageManager#fetchPinned() method is deprecated. Use MessageManager#fetchPins() instead.', + 'DeprecationWarning', + ); + + deprecationEmittedForFetchPinned = true; + } + const data = await this.client.rest.get(Routes.channelPins(this.channel.id)); const messages = new Collection(); for (const message of data) messages.set(message.id, this._add(message, cache)); @@ -219,7 +286,7 @@ class MessageManager extends CachedManager { message = this.resolveId(message); if (!message) throw new DiscordjsTypeError(ErrorCodes.InvalidType, 'message', 'MessageResolvable'); - await this.client.rest.put(Routes.channelPin(this.channel.id, message), { reason }); + await this.client.rest.put(Routes.channelMessagesPin(this.channel.id, message), { reason }); } /** @@ -232,7 +299,7 @@ class MessageManager extends CachedManager { message = this.resolveId(message); if (!message) throw new DiscordjsTypeError(ErrorCodes.InvalidType, 'message', 'MessageResolvable'); - await this.client.rest.delete(Routes.channelPin(this.channel.id, message), { reason }); + await this.client.rest.delete(Routes.channelMessagesPin(this.channel.id, message), { reason }); } /** diff --git a/packages/discord.js/typings/index.d.ts b/packages/discord.js/typings/index.d.ts index b895604c1901..27015a8c6cf5 100644 --- a/packages/discord.js/typings/index.d.ts +++ b/packages/discord.js/typings/index.d.ts @@ -5025,7 +5025,9 @@ export abstract class MessageManager extends ): Promise>; public fetch(options: MessageResolvable | FetchMessageOptions): Promise>; public fetch(options?: FetchMessagesOptions): Promise>>; + /** @deprecated Use {@link MessageManager.fetchPins} instead. */ public fetchPinned(cache?: boolean): Promise>>; + public fetchPins(options?: FetchPinnedMessagesOptions): Promise>; public react(message: MessageResolvable, emoji: EmojiIdentifierResolvable): Promise; public pin(message: MessageResolvable, reason?: string): Promise; public unpin(message: MessageResolvable, reason?: string): Promise; @@ -6349,6 +6351,23 @@ export interface FetchMessagesOptions { cache?: boolean; } +export interface FetchPinnedMessagesOptions { + before?: DateResolvable; + cache?: boolean; + limit?: number; +} + +export interface FetchPinnedMessagesResponse { + hasMore: boolean; + items: readonly MessagePin[]; +} + +export interface MessagePin { + message: Message; + get pinnedAt(): Date; + pinnedTimestamp: number; +} + export interface FetchReactionUsersOptions { type?: ReactionType; limit?: number; diff --git a/packages/discord.js/typings/index.test-d.ts b/packages/discord.js/typings/index.test-d.ts index 2316cb088f80..4507770a6c14 100644 --- a/packages/discord.js/typings/index.test-d.ts +++ b/packages/discord.js/typings/index.test-d.ts @@ -231,6 +231,7 @@ import { FileComponentData, ContainerComponentData, InteractionResponse, + FetchPinnedMessagesResponse, } from '.'; import { expectAssignable, @@ -1690,6 +1691,7 @@ declare const guildChannelManager: GuildChannelManager; expectType>>(messages.edit('1234567890', 'text')); expectType>>(messages.fetch('1234567890')); expectType>>>(messages.fetchPinned()); + expectType>>(messages.fetchPins()); expectType(message.guild); expectType(message.guildId); expectType(message.channel.messages.channel); @@ -1703,6 +1705,7 @@ declare const guildChannelManager: GuildChannelManager; expectType>(messages.edit('1234567890', 'text')); expectType>(messages.fetch('1234567890')); expectType>>(messages.fetchPinned()); + expectType>(messages.fetchPins()); expectType(message.guild); expectType(message.guildId); expectType(message.channel.messages.channel);