From fb19a368d2dfb090198afc5567634ca1cebc9d3a Mon Sep 17 00:00:00 2001 From: Jiralite <33201955+Jiralite@users.noreply.github.com> Date: Mon, 29 May 2023 17:22:18 +0100 Subject: [PATCH 1/4] types(MessageManager): allow comparison of messages again --- packages/discord.js/typings/index.d.ts | 18 +++++--- packages/discord.js/typings/index.test-d.ts | 47 +++++++++++++++------ 2 files changed, 47 insertions(+), 18 deletions(-) diff --git a/packages/discord.js/typings/index.d.ts b/packages/discord.js/typings/index.d.ts index c96a54f37db8..c50dd696dcf3 100644 --- a/packages/discord.js/typings/index.d.ts +++ b/packages/discord.js/typings/index.d.ts @@ -4002,14 +4002,13 @@ export class GuildMemberRoleManager extends DataManager; } -export class MessageManager extends CachedManager< +export abstract class MessageManager extends CachedManager< Snowflake, Message, MessageResolvable > { - private constructor(channel: TextBasedChannel, iterable?: Iterable); - public channel: If; - public crosspost(message: MessageResolvable): Promise>; + protected constructor(channel: TextBasedChannel, iterable?: Iterable); + public channel: TextBasedChannel; public delete(message: MessageResolvable): Promise; public edit( message: MessageResolvable, @@ -4023,6 +4022,15 @@ export class MessageManager extends CachedMan public unpin(message: MessageResolvable, reason?: string): Promise; } +export class DMMessageManager extends MessageManager { + public channel: DMChannel; +} + +export class GuildMessageManager extends MessageManager { + public channel: GuildTextBasedChannel; + public crosspost(message: MessageResolvable): Promise>; +} + export class PermissionOverwriteManager extends CachedManager< Snowflake, PermissionOverwrites, @@ -4189,7 +4197,7 @@ export interface TextBasedChannelFields get lastMessage(): Message | null; lastPinTimestamp: number | null; get lastPinAt(): Date | null; - messages: MessageManager; + messages: If; awaitMessageComponent( options?: AwaitMessageCollectorOptionsParams, ): Promise; diff --git a/packages/discord.js/typings/index.test-d.ts b/packages/discord.js/typings/index.test-d.ts index cd8c8771a880..2a471504da9c 100644 --- a/packages/discord.js/typings/index.test-d.ts +++ b/packages/discord.js/typings/index.test-d.ts @@ -163,6 +163,8 @@ import { ThreadManager, FetchedThreads, FetchedThreadsMore, + DMMessageManager, + GuildMessageManager, } from '.'; import { expectAssignable, expectNotAssignable, expectNotType, expectType } from 'tsd'; import type { ContextMenuCommandBuilder, SlashCommandBuilder } from '@discordjs/builders'; @@ -341,6 +343,19 @@ declare const assertIsMessage: (m: Promise) => void; client.on('messageCreate', async message => { const { client, channel } = message; + // https://github.com/discordjs/discord.js/issues/8545 + { + // These should not throw any errors when comparing messages from any source. + channel.messages.cache.filter(m => m); + (await channel.messages.fetch()).filter(m => m.author.id === message.author.id); + + if (channel.isDMBased()) { + expectType(channel.messages.channel.messages); + } else { + expectType(channel.messages.channel.messages); + } + } + if (!message.inGuild() && message.partial) { expectNotType(message); } @@ -1454,7 +1469,7 @@ declare const guildChannelManager: GuildChannelManager; if (channel.isTextBased()) { const { messages } = channel; const message = await messages.fetch('123'); - expectType>(messages); + expectType(messages); expectType>>(messages.crosspost('1234567890')); expectType>>(messages.edit('1234567890', 'text')); expectType>>(messages.fetch('1234567890')); @@ -1468,18 +1483,24 @@ declare const guildChannelManager: GuildChannelManager; { const { messages } = dmChannel; const message = await messages.fetch('123'); - expectType>(messages); - expectType>>(messages.crosspost('1234567890')); // This shouldn't even exist! - expectType>>(messages.edit('1234567890', 'text')); - expectType>>(messages.fetch('1234567890')); - expectType>>>(messages.fetchPinned()); - expectType(message.guild); - expectType(message.guildId); - expectType(message.channel.messages.channel); - - expectType>(message.mentions); - expectType(message.mentions.guild); - expectType(message.mentions.members); + expectType(messages); + expectType>(messages.edit('1234567890', 'text')); + expectType>(messages.fetch('1234567890')); + expectType>>(messages.fetchPinned()); + expectType(message.guild); + expectType(message.guildId); + expectType(message.channel.messages.channel); + expectType(message.mentions); + expectType(message.mentions.guild); + expectType | null>(message.mentions.members); + + if (messages.channel.isDMBased()) { + expectType(messages.channel); + expectType(messages.channel.messages.channel); + } + + // @ts-expect-error Crossposting is not possible in direct messages. + messages.crosspost('1234567890'); } declare const threadManager: ThreadManager; From 8e3e917f21cc97cd1728a6685e85dd600d59bce8 Mon Sep 17 00:00:00 2001 From: Jiralite <33201955+Jiralite@users.noreply.github.com> Date: Mon, 29 May 2023 18:17:23 +0100 Subject: [PATCH 2/4] feat: match TypeScript --- packages/discord.js/src/index.js | 2 ++ .../src/managers/DMMessageManager.js | 17 ++++++++++ .../src/managers/GuildMessageManager.js | 32 +++++++++++++++++++ .../discord.js/src/managers/MessageManager.js | 14 +------- .../src/structures/BaseGuildTextChannel.js | 6 ++-- .../src/structures/BaseGuildVoiceChannel.js | 6 ++-- .../discord.js/src/structures/DMChannel.js | 6 ++-- .../src/structures/ThreadChannel.js | 6 ++-- .../structures/interfaces/TextBasedChannel.js | 6 ++-- 9 files changed, 67 insertions(+), 28 deletions(-) create mode 100644 packages/discord.js/src/managers/DMMessageManager.js create mode 100644 packages/discord.js/src/managers/GuildMessageManager.js diff --git a/packages/discord.js/src/index.js b/packages/discord.js/src/index.js index c7c530ced537..737115d34fbc 100644 --- a/packages/discord.js/src/index.js +++ b/packages/discord.js/src/index.js @@ -55,6 +55,7 @@ exports.CachedManager = require('./managers/CachedManager'); exports.ChannelManager = require('./managers/ChannelManager'); exports.ClientVoiceManager = require('./client/voice/ClientVoiceManager'); exports.DataManager = require('./managers/DataManager'); +exports.DMMessageManager = require('./managers/DMMessageManager'); exports.GuildApplicationCommandManager = require('./managers/GuildApplicationCommandManager'); exports.GuildBanManager = require('./managers/GuildBanManager'); exports.GuildChannelManager = require('./managers/GuildChannelManager'); @@ -65,6 +66,7 @@ exports.GuildInviteManager = require('./managers/GuildInviteManager'); exports.GuildManager = require('./managers/GuildManager'); exports.GuildMemberManager = require('./managers/GuildMemberManager'); exports.GuildMemberRoleManager = require('./managers/GuildMemberRoleManager'); +exports.GuildMessageManager = require('./managers/GuildMessageManager'); exports.GuildScheduledEventManager = require('./managers/GuildScheduledEventManager'); exports.GuildStickerManager = require('./managers/GuildStickerManager'); exports.GuildTextThreadManager = require('./managers/GuildTextThreadManager'); diff --git a/packages/discord.js/src/managers/DMMessageManager.js b/packages/discord.js/src/managers/DMMessageManager.js new file mode 100644 index 000000000000..b2af945a2d59 --- /dev/null +++ b/packages/discord.js/src/managers/DMMessageManager.js @@ -0,0 +1,17 @@ +'use strict'; + +const MessageManager = require('./MessageManager'); + +/** + * Manages API methods for Messages and holds their cache. + * @extends {MessageManager} + */ +class DMMessageManager extends MessageManager { + /** + * The channel that the messages belong to + * @name DMMessageManager#channel + * @type {DMChannel} + */ +} + +module.exports = DMMessageManager; diff --git a/packages/discord.js/src/managers/GuildMessageManager.js b/packages/discord.js/src/managers/GuildMessageManager.js new file mode 100644 index 000000000000..9c3834058ed0 --- /dev/null +++ b/packages/discord.js/src/managers/GuildMessageManager.js @@ -0,0 +1,32 @@ +'use strict'; + +const { Routes } = require('discord-api-types/v10'); +const MessageManager = require('./MessageManager'); +const { DiscordjsTypeError, ErrorCodes } = require('../errors'); + +/** + * Manages API methods for Messages and holds their cache. + * @extends {MessageManager} + */ +class GuildMessageManager extends MessageManager { + /** + * The channel that the messages belong to + * @name GuildMessageManager#channel + * @type {GuildTextBasedChannel} + */ + + /** + * Publishes a message in an announcement channel to all channels following it, even if it's not cached. + * @param {MessageResolvable} message The message to publish + * @returns {Promise} + */ + async crosspost(message) { + message = this.resolveId(message); + if (!message) throw new DiscordjsTypeError(ErrorCodes.InvalidType, 'message', 'MessageResolvable'); + + const data = await this.client.rest.post(Routes.channelMessageCrosspost(this.channel.id, message)); + return this.cache.get(data.id) ?? this._add(data); + } +} + +module.exports = GuildMessageManager; diff --git a/packages/discord.js/src/managers/MessageManager.js b/packages/discord.js/src/managers/MessageManager.js index 28d622d2c79f..0badcc34a77a 100644 --- a/packages/discord.js/src/managers/MessageManager.js +++ b/packages/discord.js/src/managers/MessageManager.js @@ -12,6 +12,7 @@ const { resolvePartialEmoji } = require('../util/Util'); /** * Manages API methods for Messages and holds their cache. * @extends {CachedManager} + * @abstract */ class MessageManager extends CachedManager { constructor(channel, iterable) { @@ -184,19 +185,6 @@ class MessageManager extends CachedManager { return this._add(d); } - /** - * Publishes a message in an announcement channel to all channels following it, even if it's not cached. - * @param {MessageResolvable} message The message to publish - * @returns {Promise} - */ - async crosspost(message) { - message = this.resolveId(message); - if (!message) throw new DiscordjsTypeError(ErrorCodes.InvalidType, 'message', 'MessageResolvable'); - - const data = await this.client.rest.post(Routes.channelMessageCrosspost(this.channel.id, message)); - return this.cache.get(data.id) ?? this._add(data); - } - /** * Pins a message to the channel's pinned messages, even if it's not cached. * @param {MessageResolvable} message The message to pin diff --git a/packages/discord.js/src/structures/BaseGuildTextChannel.js b/packages/discord.js/src/structures/BaseGuildTextChannel.js index a8a608b3bdd0..f7d9d69889a6 100644 --- a/packages/discord.js/src/structures/BaseGuildTextChannel.js +++ b/packages/discord.js/src/structures/BaseGuildTextChannel.js @@ -2,8 +2,8 @@ const GuildChannel = require('./GuildChannel'); const TextBasedChannel = require('./interfaces/TextBasedChannel'); +const GuildMessageManager = require('../managers/GuildMessageManager'); const GuildTextThreadManager = require('../managers/GuildTextThreadManager'); -const MessageManager = require('../managers/MessageManager'); /** * Represents a text-based guild channel on Discord. @@ -16,9 +16,9 @@ class BaseGuildTextChannel extends GuildChannel { /** * A manager of the messages sent to this channel - * @type {MessageManager} + * @type {GuildMessageManager} */ - this.messages = new MessageManager(this); + this.messages = new GuildMessageManager(this); /** * A manager of the threads belonging to this channel diff --git a/packages/discord.js/src/structures/BaseGuildVoiceChannel.js b/packages/discord.js/src/structures/BaseGuildVoiceChannel.js index de80dfeaaed6..220ac6c8d83b 100644 --- a/packages/discord.js/src/structures/BaseGuildVoiceChannel.js +++ b/packages/discord.js/src/structures/BaseGuildVoiceChannel.js @@ -4,7 +4,7 @@ const { Collection } = require('@discordjs/collection'); const { PermissionFlagsBits } = require('discord-api-types/v10'); const GuildChannel = require('./GuildChannel'); const TextBasedChannel = require('./interfaces/TextBasedChannel'); -const MessageManager = require('../managers/MessageManager'); +const GuildMessageManager = require('../managers/GuildMessageManager'); /** * Represents a voice-based guild channel on Discord. @@ -16,9 +16,9 @@ class BaseGuildVoiceChannel extends GuildChannel { super(guild, data, client, false); /** * A manager of the messages sent to this channel - * @type {MessageManager} + * @type {GuildMessageManager} */ - this.messages = new MessageManager(this); + this.messages = new GuildMessageManager(this); /** * If the guild considers this channel NSFW diff --git a/packages/discord.js/src/structures/DMChannel.js b/packages/discord.js/src/structures/DMChannel.js index 8c13f7550058..0ade9aa0491f 100644 --- a/packages/discord.js/src/structures/DMChannel.js +++ b/packages/discord.js/src/structures/DMChannel.js @@ -4,7 +4,7 @@ const { userMention } = require('@discordjs/builders'); const { ChannelType } = require('discord-api-types/v10'); const { BaseChannel } = require('./BaseChannel'); const TextBasedChannel = require('./interfaces/TextBasedChannel'); -const MessageManager = require('../managers/MessageManager'); +const DMMessageManager = require('../managers/DMMessageManager'); const Partials = require('../util/Partials'); /** @@ -21,9 +21,9 @@ class DMChannel extends BaseChannel { /** * A manager of the messages belonging to this channel - * @type {MessageManager} + * @type {DMMessageManager} */ - this.messages = new MessageManager(this); + this.messages = new DMMessageManager(this); } _patch(data) { diff --git a/packages/discord.js/src/structures/ThreadChannel.js b/packages/discord.js/src/structures/ThreadChannel.js index d57fd9dd23f0..96b408701ade 100644 --- a/packages/discord.js/src/structures/ThreadChannel.js +++ b/packages/discord.js/src/structures/ThreadChannel.js @@ -4,7 +4,7 @@ const { ChannelType, PermissionFlagsBits, Routes, ChannelFlags } = require('disc const { BaseChannel } = require('./BaseChannel'); const TextBasedChannel = require('./interfaces/TextBasedChannel'); const { DiscordjsRangeError, ErrorCodes } = require('../errors'); -const MessageManager = require('../managers/MessageManager'); +const GuildMessageManager = require('../managers/GuildMessageManager'); const ThreadMemberManager = require('../managers/ThreadMemberManager'); const ChannelFlagsBitField = require('../util/ChannelFlagsBitField'); @@ -31,9 +31,9 @@ class ThreadChannel extends BaseChannel { /** * A manager of the messages sent to this thread - * @type {MessageManager} + * @type {GuildMessageManager} */ - this.messages = new MessageManager(this); + this.messages = new GuildMessageManager(this); /** * A manager of the members that are part of this thread diff --git a/packages/discord.js/src/structures/interfaces/TextBasedChannel.js b/packages/discord.js/src/structures/interfaces/TextBasedChannel.js index 97bc337313ae..cf455b9854b3 100644 --- a/packages/discord.js/src/structures/interfaces/TextBasedChannel.js +++ b/packages/discord.js/src/structures/interfaces/TextBasedChannel.js @@ -17,9 +17,9 @@ class TextBasedChannel { constructor() { /** * A manager of the messages sent to this channel - * @type {MessageManager} + * @type {GuildMessageManager} */ - this.messages = new MessageManager(this); + this.messages = new GuildMessageManager(this); /** * The channel's last message id, if one was sent @@ -410,4 +410,4 @@ module.exports = TextBasedChannel; // Fixes Circular // eslint-disable-next-line import/order -const MessageManager = require('../../managers/MessageManager'); +const GuildMessageManager = require('../../managers/GuildMessageManager'); From 9a12fe58b9f47a9627f52253ddd61546127ed90f Mon Sep 17 00:00:00 2001 From: Jiralite <33201955+Jiralite@users.noreply.github.com> Date: Mon, 29 May 2023 21:14:52 +0100 Subject: [PATCH 3/4] docs: update wording --- packages/discord.js/src/managers/DMMessageManager.js | 2 +- packages/discord.js/src/managers/GuildMessageManager.js | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/packages/discord.js/src/managers/DMMessageManager.js b/packages/discord.js/src/managers/DMMessageManager.js index b2af945a2d59..f0b3a338c92e 100644 --- a/packages/discord.js/src/managers/DMMessageManager.js +++ b/packages/discord.js/src/managers/DMMessageManager.js @@ -3,7 +3,7 @@ const MessageManager = require('./MessageManager'); /** - * Manages API methods for Messages and holds their cache. + * Manages API methods for messages in direct message channels and holds their cache. * @extends {MessageManager} */ class DMMessageManager extends MessageManager { diff --git a/packages/discord.js/src/managers/GuildMessageManager.js b/packages/discord.js/src/managers/GuildMessageManager.js index 9c3834058ed0..c9999827480a 100644 --- a/packages/discord.js/src/managers/GuildMessageManager.js +++ b/packages/discord.js/src/managers/GuildMessageManager.js @@ -5,7 +5,7 @@ const MessageManager = require('./MessageManager'); const { DiscordjsTypeError, ErrorCodes } = require('../errors'); /** - * Manages API methods for Messages and holds their cache. + * Manages API methods for messages in a guild and holds their cache. * @extends {MessageManager} */ class GuildMessageManager extends MessageManager { From f95a4c685880fc1066d1d4b3661b2d5e2e2b9d64 Mon Sep 17 00:00:00 2001 From: Jiralite <33201955+Jiralite@users.noreply.github.com> Date: Mon, 29 May 2023 21:15:57 +0100 Subject: [PATCH 4/4] chore: revert breaking change --- .../src/managers/GuildMessageManager.js | 15 --------------- .../discord.js/src/managers/MessageManager.js | 13 +++++++++++++ 2 files changed, 13 insertions(+), 15 deletions(-) diff --git a/packages/discord.js/src/managers/GuildMessageManager.js b/packages/discord.js/src/managers/GuildMessageManager.js index c9999827480a..7a93c99f1ed2 100644 --- a/packages/discord.js/src/managers/GuildMessageManager.js +++ b/packages/discord.js/src/managers/GuildMessageManager.js @@ -1,8 +1,6 @@ 'use strict'; -const { Routes } = require('discord-api-types/v10'); const MessageManager = require('./MessageManager'); -const { DiscordjsTypeError, ErrorCodes } = require('../errors'); /** * Manages API methods for messages in a guild and holds their cache. @@ -14,19 +12,6 @@ class GuildMessageManager extends MessageManager { * @name GuildMessageManager#channel * @type {GuildTextBasedChannel} */ - - /** - * Publishes a message in an announcement channel to all channels following it, even if it's not cached. - * @param {MessageResolvable} message The message to publish - * @returns {Promise} - */ - async crosspost(message) { - message = this.resolveId(message); - if (!message) throw new DiscordjsTypeError(ErrorCodes.InvalidType, 'message', 'MessageResolvable'); - - const data = await this.client.rest.post(Routes.channelMessageCrosspost(this.channel.id, message)); - return this.cache.get(data.id) ?? this._add(data); - } } module.exports = GuildMessageManager; diff --git a/packages/discord.js/src/managers/MessageManager.js b/packages/discord.js/src/managers/MessageManager.js index 0badcc34a77a..ea05b1d19418 100644 --- a/packages/discord.js/src/managers/MessageManager.js +++ b/packages/discord.js/src/managers/MessageManager.js @@ -185,6 +185,19 @@ class MessageManager extends CachedManager { return this._add(d); } + /** + * Publishes a message in an announcement channel to all channels following it, even if it's not cached. + * @param {MessageResolvable} message The message to publish + * @returns {Promise} + */ + async crosspost(message) { + message = this.resolveId(message); + if (!message) throw new DiscordjsTypeError(ErrorCodes.InvalidType, 'message', 'MessageResolvable'); + + const data = await this.client.rest.post(Routes.channelMessageCrosspost(this.channel.id, message)); + return this.cache.get(data.id) ?? this._add(data); + } + /** * Pins a message to the channel's pinned messages, even if it's not cached. * @param {MessageResolvable} message The message to pin