diff --git a/src/client/actions/MessageUpdate.js b/src/client/actions/MessageUpdate.js
index 7667dea4b..b0e0b8a47 100644
--- a/src/client/actions/MessageUpdate.js
+++ b/src/client/actions/MessageUpdate.js
@@ -9,7 +9,7 @@ class MessageUpdateAction extends Action {
const { id, channel_id, guild_id, author, timestamp, type } = data;
const message = this.getMessage({ id, channel_id, guild_id, author, timestamp, type }, channel);
if (message) {
- const old = message.patch(data);
+ const old = message._update(data, true);
return {
old,
updated: message,
diff --git a/src/structures/Message.js b/src/structures/Message.js
index 1b958dfa3..54b2b3cac 100644
--- a/src/structures/Message.js
+++ b/src/structures/Message.js
@@ -47,7 +47,7 @@ class Message extends Base {
if (data) this._patch(data);
}
- _patch(data) {
+ _patch(data, partial = false) {
/**
* The message's id
* @type {Snowflake}
@@ -121,121 +121,167 @@ class Message extends Base {
this.tts = null;
}
- /**
- * A random number or string used for checking message delivery
- * This is only received after the message was sent successfully, and
- * lost if re-fetched
- * @type {?string}
- */
- this.nonce = 'nonce' in data ? data.nonce : null;
-
- /**
- * A list of embeds in the message - e.g. YouTube Player
- * @type {MessageEmbed[]}
- */
- this.embeds = data.embeds?.map(e => new Embed(e, true)) ?? [];
-
- /**
- * A list of MessageActionRows in the message
- * @type {MessageActionRow[]}
- */
- this.components = data.components?.map(c => BaseMessageComponent.create(c, this.client)) ?? [];
-
- /**
- * A collection of attachments in the message - e.g. Pictures - mapped by their ids
- * @type {Collection}
- */
- this.attachments = new Collection();
- if (data.attachments) {
- for (const attachment of data.attachments) {
- this.attachments.set(attachment.id, new MessageAttachment(attachment.url, attachment.filename, attachment));
- }
+ if (!partial) {
+ /**
+ * A random number or string used for checking message delivery
+ * This is only received after the message was sent successfully, and
+ * lost if re-fetched
+ * @type {?string}
+ */
+ this.nonce = 'nonce' in data ? data.nonce : null;
}
- /**
- * A collection of (partial) stickers in the message
- * @type {Collection}
- */
- this.stickers = new Collection(
- (data.sticker_items ?? data.stickers)?.map(s => [s.id, new Sticker(this.client, s)]),
- );
-
- /**
- * The timestamp the message was sent at
- * @type {number}
- */
- this.createdTimestamp = SnowflakeUtil.deconstruct(this.id).timestamp;
-
- /**
- * The timestamp the message was last edited at (if applicable)
- * @type {?number}
- */
- this.editedTimestamp = data.edited_timestamp ? new Date(data.edited_timestamp).getTime() : null;
-
- /**
- * A manager of the reactions belonging to this message
- * @type {ReactionManager}
- */
- this.reactions = new ReactionManager(this);
- if (data.reactions?.length > 0) {
- for (const reaction of data.reactions) {
- this.reactions._add(reaction);
- }
+ if ('embeds' in data || !partial) {
+ /**
+ * A list of embeds in the message - e.g. YouTube Player
+ * @type {MessageEmbed[]}
+ */
+ this.embeds = data.embeds?.map(e => new Embed(e, true)) ?? [];
+ } else {
+ this.embeds = this.embeds.slice();
}
- /**
- * All valid mentions that the message contains
- * @type {MessageMentions}
- */
- this.mentions = new Mentions(
- this,
- data.mentions,
- data.mention_roles,
- data.mention_everyone,
- data.mention_channels,
- data.referenced_message?.author,
- );
+ if ('components' in data || !partial) {
+ /**
+ * A list of MessageActionRows in the message
+ * @type {MessageActionRow[]}
+ */
+ this.components = data.components?.map(c => BaseMessageComponent.create(c, this.client)) ?? [];
+ } else {
+ this.components = this.components.slice();
+ }
- /**
- * The id of the webhook that sent the message, if applicable
- * @type {?Snowflake}
- */
- this.webhookId = data.webhook_id ?? null;
-
- /**
- * Supplemental application information for group activities
- * @type {?ClientApplication}
- */
- this.groupActivityApplication = data.application ? new ClientApplication(this.client, data.application) : null;
-
- /**
- * The id of the application of the interaction that sent this message, if any
- * @type {?Snowflake}
- */
- this.applicationId = data.application_id ?? null;
-
- /**
- * Group activity
- * @type {?MessageActivity}
- */
- this.activity = data.activity
- ? {
- partyId: data.activity.party_id,
- type: data.activity.type,
+ if ('attachments' in data || !partial) {
+ /**
+ * A collection of attachments in the message - e.g. Pictures - mapped by their ids
+ * @type {Collection}
+ */
+ this.attachments = new Collection();
+ if (data.attachments) {
+ for (const attachment of data.attachments) {
+ this.attachments.set(attachment.id, new MessageAttachment(attachment.url, attachment.filename, attachment));
}
- : null;
+ }
+ } else {
+ this.attachments = new Collection(this.attachemnts);
+ }
+ if ('sticker_itesm' in data || 'stickers' in data || !partial) {
+ /**
+ * A collection of stickers in the message
+ * @type {Collection}
+ */
+ this.stickers = new Collection(
+ (data.sticker_items ?? data.stickers)?.map(s => [s.id, new Sticker(this.client, s)]),
+ );
+ } else {
+ this.stickers = new Collection(this.stickers);
+ }
+
+ if (!partial) {
+ /**
+ * The timestamp the message was sent at
+ * @type {number}
+ */
+ this.createdTimestamp = SnowflakeUtil.deconstruct(this.id).timestamp;
+ }
+
+ if ('edited_timestamp' in data || !partial) {
+ /**
+ * The timestamp the message was last edited at (if applicable)
+ * @type {?number}
+ */
+ this.editedTimestamp = data.edited_timestamp ? new Date(data.edited_timestamp).getTime() : null;
+ }
+
+ if ('reactions' in data || !partial) {
+ /**
+ * A manager of the reactions belonging to this message
+ * @type {ReactionManager}
+ */
+ this.reactions = new ReactionManager(this);
+ if (data.reactions?.length > 0) {
+ for (const reaction of data.reactions) {
+ this.reactions._add(reaction);
+ }
+ }
+ }
+
+ if (!partial) {
+ /**
+ * All valid mentions that the message contains
+ * @type {MessageMentions}
+ */
+ this.mentions = new Mentions(
+ this,
+ data.mentions,
+ data.mention_roles,
+ data.mention_everyone,
+ data.mention_channels,
+ data.referenced_message?.author,
+ );
+ } else {
+ this.mentions = new Mentions(
+ this,
+ data.mentions ?? this.mentions.users,
+ data.mention_roles ?? this.mentions.roles,
+ data.mention_everyone ?? this.mentions.everyone,
+ data.mention_channels ?? this.mentions.crosspostedChannels,
+ data.referenced_message?.author ?? this.mentions.repliedUser,
+ );
+ }
+
+ if ('webhook_id' in data || !partial) {
+ /**
+ * The id of the webhook that sent the message, if applicable
+ * @type {?Snowflake}
+ */
+ this.webhookId = data.webhook_id ?? null;
+ }
+
+ if ('application' in data || !partial) {
+ /**
+ * Supplemental application information for group activities
+ * @type {?ClientApplication}
+ */
+ this.groupActivityApplication = data.application ? new ClientApplication(this.client, data.application) : null;
+ }
+
+ if ('application_id' in data || !partial) {
+ /**
+ * The id of the application of the interaction that sent this message, if any
+ * @type {?Snowflake}
+ */
+ this.applicationId = data.application_id ?? null;
+ }
+
+ if ('activity' in data || !partial) {
+ /**
+ * Group activity
+ * @type {?MessageActivity}
+ */
+ this.activity = data.activity
+ ? {
+ partyId: data.activity.party_id,
+ type: data.activity.type,
+ }
+ : null;
+ }
if (this.member && data.member) {
this.member._patch(data.member);
} else if (data.member && this.guild && this.author) {
this.guild.members._add(Object.assign(data.member, { user: this.author }));
}
- /**
- * Flags that are applied to the message
- * @type {Readonly}
- */
- this.flags = new MessageFlags(data.flags).freeze();
+ if ('flags' in data || !partial) {
+ /**
+ * Flags that are applied to the message
+ * @type {Readonly}
+ */
+ this.flags = new MessageFlags(data.flags).freeze();
+ } else {
+ this.flags = new MessageFlags(this.flags).freeze();
+ }
/**
* Reference data sent in a message that contains ids identifying the referenced message
@@ -245,17 +291,19 @@ class Message extends Base {
* @property {?string} messageId The message's id that was referenced
*/
- /**
- * Message reference data
- * @type {?MessageReference}
- */
- this.reference = data.message_reference
- ? {
- channelId: data.message_reference.channel_id,
- guildId: data.message_reference.guild_id,
- messageId: data.message_reference.message_id,
- }
- : null;
+ if ('message_reference' in data || !partial) {
+ /**
+ * Message reference data
+ * @type {?MessageReference}
+ */
+ this.reference = data.message_reference
+ ? {
+ channelId: data.message_reference.channel_id,
+ guildId: data.message_reference.guild_id,
+ messageId: data.message_reference.message_id,
+ }
+ : null;
+ }
if (data.referenced_message) {
this.channel.messages._add(data.referenced_message);
@@ -286,6 +334,12 @@ class Message extends Base {
}
}
+ _update(data, partial = false) {
+ const clone = this._clone();
+ this._patch(data, partial);
+ return clone;
+ }
+
/**
* Whether or not this message is a partial
* @type {boolean}
@@ -295,47 +349,6 @@ class Message extends Base {
return typeof this.content !== 'string' || !this.author;
}
- /**
- * Updates the message and returns the old message.
- * @param {APIMessage} data Raw Discord message update data
- * @returns {Message}
- * @private
- */
- patch(data) {
- const clone = this._clone();
-
- if (data.edited_timestamp) this.editedTimestamp = new Date(data.edited_timestamp).getTime();
- if ('content' in data) this.content = data.content;
- if ('pinned' in data) this.pinned = data.pinned;
- if ('tts' in data) this.tts = data.tts;
- if ('thread' in data) this.thread = this.client.channels._add(data.thread);
-
- if ('attachments' in data) {
- this.attachments = new Collection();
- for (const attachment of data.attachments) {
- this.attachments.set(attachment.id, new MessageAttachment(attachment.url, attachment.filename, attachment));
- }
- } else {
- this.attachments = new Collection(this.attachments);
- }
-
- this.embeds = data.embeds?.map(e => new Embed(e, true)) ?? this.embeds.slice();
- this.components = data.components?.map(c => BaseMessageComponent.create(c, this.client)) ?? this.components.slice();
-
- this.mentions = new Mentions(
- this,
- data.mentions ?? this.mentions.users,
- data.mention_roles ?? this.mentions.roles,
- data.mention_everyone ?? this.mentions.everyone,
- data.mention_channels ?? this.mentions.crosspostedChannels,
- data.referenced_message?.author ?? this.mentions.repliedUser,
- );
-
- this.flags = new MessageFlags(data.flags ?? 0).freeze();
-
- return clone;
- }
-
/**
* Represents the author of the message as a guild member.
* Only available if the message comes from a guild where the author is still a member
diff --git a/typings/index.d.ts b/typings/index.d.ts
index b18c2c8a2..c99166224 100644
--- a/typings/index.d.ts
+++ b/typings/index.d.ts
@@ -969,7 +969,8 @@ export class LimitedCollection extends Collection {
export class Message extends Base {
public constructor(client: Client, data: unknown, channel: TextChannel | DMChannel | NewsChannel | ThreadChannel);
- private patch(data: unknown): Message;
+ private _patch(data: unknown, partial?: boolean): Message;
+ private _update(data: unknown, partial?: boolean): Message;
public activity: MessageActivity | null;
public applicationId: Snowflake | null;