Skip to content

Commit f469f74

Browse files
authored
feat(MessageManager): New pinned messages routes (#10993)
feat(MessageManager)!: New pinned messages routes (#10989) BREAKING CHANGE: `fetchPinned()` has been renamed to `fetchPins()`, which is a paginated endpoint to fetch pinned messages.
1 parent 90d3b28 commit f469f74

File tree

3 files changed

+95
-6
lines changed

3 files changed

+95
-6
lines changed

packages/discord.js/src/managers/MessageManager.js

Lines changed: 73 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,6 @@
11
'use strict';
22

3+
const process = require('node:process');
34
const { Collection } = require('@discordjs/collection');
45
const { makeURLSearchParams } = require('@discordjs/rest');
56
const { Routes } = require('discord-api-types/v10');
@@ -10,6 +11,8 @@ const MessagePayload = require('../structures/MessagePayload');
1011
const { MakeCacheOverrideSymbol } = require('../util/Symbols');
1112
const { resolvePartialEmoji } = require('../util/Util');
1213

14+
let deprecationEmittedForFetchPinned = false;
15+
1316
/**
1417
* Manages API methods for Messages and holds their cache.
1518
* @extends {CachedManager}
@@ -116,19 +119,83 @@ class MessageManager extends CachedManager {
116119
return data.reduce((_data, message) => _data.set(message.id, this._add(message, options.cache)), new Collection());
117120
}
118121

122+
/**
123+
* Options used to fetch pinned messages.
124+
*
125+
* @typedef {Object} FetchPinnedMessagesOptions
126+
* @property {DateResolvable} [before] Consider only pinned messages before this time
127+
* @property {number} [limit] The maximum number of pinned messages to return
128+
* @property {boolean} [cache] Whether to cache the pinned messages
129+
*/
130+
131+
/**
132+
* Data returned from fetching pinned messages.
133+
*
134+
* @typedef {Object} FetchPinnedMessagesResponse
135+
* @property {MessagePin[]} items The pinned messages
136+
* @property {boolean} hasMore Whether there are additional pinned messages that require a subsequent call
137+
*/
138+
139+
/**
140+
* Pinned message data returned from fetching pinned messages.
141+
*
142+
* @typedef {Object} MessagePin
143+
* @property {Date} pinnedAt The time the message was pinned at
144+
* @property {number} pinnedTimestamp The timestamp the message was pinned at
145+
* @property {Message} message The pinned message
146+
*/
147+
119148
/**
120149
* Fetches the pinned messages of this channel and returns a collection of them.
121150
* <info>The returned Collection does not contain any reaction data of the messages.
122151
* Those need to be fetched separately.</info>
123-
* @param {boolean} [cache=true] Whether to cache the message(s)
124-
* @returns {Promise<Collection<Snowflake, Message>>}
152+
*
153+
* @param {FetchPinnedMessagesOptions} [options={}] Options for fetching pinned messages
154+
* @returns {Promise<FetchPinnedMessagesResponse>}
125155
* @example
126156
* // Get pinned messages
127-
* channel.messages.fetchPinned()
128-
* .then(messages => console.log(`Received ${messages.size} messages`))
157+
* channel.messages.fetchPins()
158+
* .then(messages => console.log(`Received ${messages.items.length} messages`))
129159
* .catch(console.error);
130160
*/
161+
async fetchPins(options = {}) {
162+
const data = await this.client.rest.get(Routes.channelMessagesPins(this.channel.id), {
163+
query: makeURLSearchParams({
164+
...options,
165+
before: options.before && new Date(options.before).toISOString(),
166+
}),
167+
});
168+
169+
return {
170+
items: data.items.map(item => ({
171+
pinnedTimestamp: Date.parse(item.pinned_at),
172+
get pinnedAt() {
173+
return new Date(this.pinnedTimestamp);
174+
},
175+
message: this._add(item.message, options.cache),
176+
})),
177+
hasMore: data.has_more,
178+
};
179+
}
180+
181+
/**
182+
* Fetches the pinned messages of this channel and returns a collection of them.
183+
* <info>The returned Collection does not contain any reaction data of the messages.
184+
* Those need to be fetched separately.</info>
185+
* @param {boolean} [cache=true] Whether to cache the message(s)
186+
* @deprecated Use {@link MessageManager#fetchPins} instead.
187+
* @returns {Promise<Collection<Snowflake, Message>>}
188+
*/
131189
async fetchPinned(cache = true) {
190+
if (!deprecationEmittedForFetchPinned) {
191+
process.emitWarning(
192+
'The MessageManager#fetchPinned() method is deprecated. Use MessageManager#fetchPins() instead.',
193+
'DeprecationWarning',
194+
);
195+
196+
deprecationEmittedForFetchPinned = true;
197+
}
198+
132199
const data = await this.client.rest.get(Routes.channelPins(this.channel.id));
133200
const messages = new Collection();
134201
for (const message of data) messages.set(message.id, this._add(message, cache));
@@ -219,7 +286,7 @@ class MessageManager extends CachedManager {
219286
message = this.resolveId(message);
220287
if (!message) throw new DiscordjsTypeError(ErrorCodes.InvalidType, 'message', 'MessageResolvable');
221288

222-
await this.client.rest.put(Routes.channelPin(this.channel.id, message), { reason });
289+
await this.client.rest.put(Routes.channelMessagesPin(this.channel.id, message), { reason });
223290
}
224291

225292
/**
@@ -232,7 +299,7 @@ class MessageManager extends CachedManager {
232299
message = this.resolveId(message);
233300
if (!message) throw new DiscordjsTypeError(ErrorCodes.InvalidType, 'message', 'MessageResolvable');
234301

235-
await this.client.rest.delete(Routes.channelPin(this.channel.id, message), { reason });
302+
await this.client.rest.delete(Routes.channelMessagesPin(this.channel.id, message), { reason });
236303
}
237304

238305
/**

packages/discord.js/typings/index.d.ts

Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -5025,7 +5025,9 @@ export abstract class MessageManager<InGuild extends boolean = boolean> extends
50255025
): Promise<Message<InGuild>>;
50265026
public fetch(options: MessageResolvable | FetchMessageOptions): Promise<Message<InGuild>>;
50275027
public fetch(options?: FetchMessagesOptions): Promise<Collection<Snowflake, Message<InGuild>>>;
5028+
/** @deprecated Use {@link MessageManager.fetchPins} instead. */
50285029
public fetchPinned(cache?: boolean): Promise<Collection<Snowflake, Message<InGuild>>>;
5030+
public fetchPins(options?: FetchPinnedMessagesOptions): Promise<FetchPinnedMessagesResponse<InGuild>>;
50295031
public react(message: MessageResolvable, emoji: EmojiIdentifierResolvable): Promise<void>;
50305032
public pin(message: MessageResolvable, reason?: string): Promise<void>;
50315033
public unpin(message: MessageResolvable, reason?: string): Promise<void>;
@@ -6349,6 +6351,23 @@ export interface FetchMessagesOptions {
63496351
cache?: boolean;
63506352
}
63516353

6354+
export interface FetchPinnedMessagesOptions {
6355+
before?: DateResolvable;
6356+
cache?: boolean;
6357+
limit?: number;
6358+
}
6359+
6360+
export interface FetchPinnedMessagesResponse<InGuild extends boolean = boolean> {
6361+
hasMore: boolean;
6362+
items: readonly MessagePin<InGuild>[];
6363+
}
6364+
6365+
export interface MessagePin<InGuild extends boolean = boolean> {
6366+
message: Message<InGuild>;
6367+
get pinnedAt(): Date;
6368+
pinnedTimestamp: number;
6369+
}
6370+
63526371
export interface FetchReactionUsersOptions {
63536372
type?: ReactionType;
63546373
limit?: number;

packages/discord.js/typings/index.test-d.ts

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -231,6 +231,7 @@ import {
231231
FileComponentData,
232232
ContainerComponentData,
233233
InteractionResponse,
234+
FetchPinnedMessagesResponse,
234235
} from '.';
235236
import {
236237
expectAssignable,
@@ -1690,6 +1691,7 @@ declare const guildChannelManager: GuildChannelManager;
16901691
expectType<Promise<Message<true>>>(messages.edit('1234567890', 'text'));
16911692
expectType<Promise<Message<true>>>(messages.fetch('1234567890'));
16921693
expectType<Promise<Collection<Snowflake, Message<true>>>>(messages.fetchPinned());
1694+
expectType<Promise<FetchPinnedMessagesResponse<true>>>(messages.fetchPins());
16931695
expectType<Guild>(message.guild);
16941696
expectType<Snowflake>(message.guildId);
16951697
expectType<GuildTextBasedChannel>(message.channel.messages.channel);
@@ -1703,6 +1705,7 @@ declare const guildChannelManager: GuildChannelManager;
17031705
expectType<Promise<Message>>(messages.edit('1234567890', 'text'));
17041706
expectType<Promise<Message>>(messages.fetch('1234567890'));
17051707
expectType<Promise<Collection<Snowflake, Message>>>(messages.fetchPinned());
1708+
expectType<Promise<FetchPinnedMessagesResponse>>(messages.fetchPins());
17061709
expectType<Guild | null>(message.guild);
17071710
expectType<Snowflake | null>(message.guildId);
17081711
expectType<DMChannel | PartialGroupDMChannel | GuildTextBasedChannel>(message.channel.messages.channel);

0 commit comments

Comments
 (0)