feat(MessageManager)!: New pinned messages routes (#10989)

BREAKING CHANGE: `fetchPinned()` has been renamed to `fetchPins()`, which is a paginated endpoint to fetch pinned messages.
This commit is contained in:
Jiralite
2025-07-15 16:13:24 +01:00
committed by GitHub
parent 5a611be8de
commit d03cacbde4
3 changed files with 71 additions and 14 deletions

View File

@@ -123,24 +123,63 @@ 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.
* <info>The returned Collection does not contain any reaction data of the messages.
* Those need to be fetched separately.</info>
*
* @param {boolean} [cache=true] Whether to cache the message(s)
* @returns {Promise<Collection<Snowflake, Message>>}
* @param {FetchPinnedMessagesOptions} [options={}] Options for fetching pinned messages
* @returns {Promise<FetchPinnedMessagesResponse>}
* @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 fetchPinned(cache = 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));
return messages;
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,
};
}
/**
@@ -221,7 +260,7 @@ class MessageManager extends CachedManager {
const messageId = this.resolveId(message);
if (!messageId) throw new DiscordjsTypeError(ErrorCodes.InvalidType, 'message', 'MessageResolvable');
await this.client.rest.put(Routes.channelPin(this.channel.id, messageId), { reason });
await this.client.rest.put(Routes.channelMessagesPin(this.channel.id, messageId), { reason });
}
/**
@@ -235,7 +274,7 @@ class MessageManager extends CachedManager {
const messageId = this.resolveId(message);
if (!messageId) throw new DiscordjsTypeError(ErrorCodes.InvalidType, 'message', 'MessageResolvable');
await this.client.rest.delete(Routes.channelPin(this.channel.id, messageId), { reason });
await this.client.rest.delete(Routes.channelMessagesPin(this.channel.id, messageId), { reason });
}
/**

View File

@@ -4516,7 +4516,7 @@ export abstract class MessageManager<InGuild extends boolean = boolean> extends
): Promise<Message<InGuild>>;
public fetch(options: FetchMessageOptions | MessageResolvable): Promise<Message<InGuild>>;
public fetch(options?: FetchMessagesOptions): Promise<Collection<Snowflake, Message<InGuild>>>;
public fetchPinned(cache?: boolean): Promise<Collection<Snowflake, Message<InGuild>>>;
public fetchPins(options?: FetchPinnedMessagesOptions): Promise<FetchPinnedMessagesResponse<InGuild>>;
public react(message: MessageResolvable, emoji: EmojiIdentifierResolvable): Promise<void>;
public pin(message: MessageResolvable, reason?: string): Promise<void>;
public unpin(message: MessageResolvable, reason?: string): Promise<void>;
@@ -5800,6 +5800,23 @@ export interface FetchMessagesOptions {
limit?: number;
}
export interface FetchPinnedMessagesOptions {
before?: DateResolvable;
cache?: boolean;
limit?: number;
}
export interface FetchPinnedMessagesResponse<InGuild extends boolean = boolean> {
hasMore: boolean;
items: readonly MessagePin<InGuild>[];
}
export interface MessagePin<InGuild extends boolean = boolean> {
message: Message<InGuild>;
get pinnedAt(): Date;
pinnedTimestamp: number;
}
export interface FetchReactionUsersOptions {
after?: Snowflake;
limit?: number;

View File

@@ -99,6 +99,7 @@ import type {
Entitlement,
FetchedThreads,
FetchedThreadsMore,
FetchPinnedMessagesResponse,
FileComponentData,
ForumChannel,
Guild,
@@ -1756,7 +1757,7 @@ declare const guildChannelManager: GuildChannelManager;
expectType<Promise<Message<true>>>(messages.crosspost('1234567890'));
expectType<Promise<Message<true>>>(messages.edit('1234567890', 'text'));
expectType<Promise<Message<true>>>(messages.fetch('1234567890'));
expectType<Promise<Collection<Snowflake, Message<true>>>>(messages.fetchPinned());
expectType<Promise<FetchPinnedMessagesResponse<true>>>(messages.fetchPins());
expectType<Guild>(message.guild);
expectType<Snowflake>(message.guildId);
expectType<GuildTextBasedChannel>(message.channel.messages.channel);
@@ -1769,7 +1770,7 @@ declare const guildChannelManager: GuildChannelManager;
expectType<DMMessageManager>(messages);
expectType<Promise<Message>>(messages.edit('1234567890', 'text'));
expectType<Promise<Message>>(messages.fetch('1234567890'));
expectType<Promise<Collection<Snowflake, Message>>>(messages.fetchPinned());
expectType<Promise<FetchPinnedMessagesResponse>>(messages.fetchPins());
expectType<Guild | null>(message.guild);
expectType<Snowflake | null>(message.guildId);
expectType<DMChannel | GuildTextBasedChannel | PartialGroupDMChannel>(message.channel.messages.channel);