diff --git a/src/structures/Webhook.js b/src/structures/Webhook.js index c51b3b2a0bd6..66a6e650e4b1 100644 --- a/src/structures/Webhook.js +++ b/src/structures/Webhook.js @@ -82,8 +82,9 @@ class Webhook { * @property {string} [username=this.name] Username override for the message * @property {string} [avatarURL] Avatar URL override for the message * @property {boolean} [tts=false] Whether or not the message should be spoken aloud + * @property {StringResolvable} [content] The content for the message * @property {string} [nonce=''] The nonce for the message - * @property {Object[]} [embeds] An array of embeds for the message + * @property {MessageEmbed[]|Object[]} [embeds] An array of embeds for the message * @property {MessageMentionOptions} [allowedMentions] Which mentions should be parsed from the message content * (see [here](https://discord.com/developers/docs/resources/channel#embed-object) for more details) * @property {FileOptions[]|string[]} [files] Files to send with the message @@ -92,6 +93,15 @@ class Webhook { * it exceeds the character limit. If an object is provided, these are the options for splitting the message. */ + /** + * Options that can be passed into editMessage. + * @typedef {Object} WebhookEditMessageOptions + * @property {MessageEmbed[]|Object[]} [embeds] See {@link WebhookMessageOptions#embeds} + * @property {StringResolvable} [content] See {@link WebhookMessageOptions#content} + * @property {FileOptions[]|string[]} [files] See {@link WebhookMessageOptions#files} + * @property {MessageMentionOptions} [allowedMentions] See {@link WebhookMessageOptions#allowedMentions} + */ + /** * Sends a message with this webhook. * @param {StringResolvable|APIMessage} [content=''] The content to send @@ -216,6 +226,34 @@ class Webhook { return this; } + /** + * Edits a message that was sent by this webhook. + * @param {MessageResolvable} message The message to edit + * @param {StringResolvable|APIMessage} [content] The new content for the message + * @param {WebhookEditMessageOptions|MessageEmbed|MessageEmbed[]} [options] The options to provide + * @returns {Promise} Returns the raw message data if the webhook was instantiated as a + * {@link WebhookClient} or if the channel is uncached, otherwise a {@link Message} will be returned + */ + async editMessage(message, content, options) { + const { data, files } = await ( + content.resolveData?.() ?? APIMessage.create(this, content, options).resolveData() + ).resolveFiles(); + const d = await this.client.api + .webhooks(this.id, this.token) + .messages(typeof message === 'string' ? message : message.id) + .patch({ data, files }); + + const messageManager = this.client.channels?.cache.get(d.channel_id)?.messages; + if (!messageManager) return d; + + const existing = messageManager.cache.get(d.id); + if (!existing) return messageManager.add(d); + + const clone = existing._clone(); + clone._patch(d); + return clone; + } + /** * Deletes the webhook. * @param {string} [reason] Reason for deleting this webhook @@ -224,6 +262,19 @@ class Webhook { delete(reason) { return this.client.api.webhooks(this.id, this.token).delete({ reason }); } + + /** + * Delete a message that was sent by this webhook. + * @param {MessageResolvable} message The message to delete + * @returns {Promise} + */ + async deleteMessage(message) { + await this.client.api + .webhooks(this.id, this.token) + .messages(typeof message === 'string' ? message : message.id) + .delete(); + } + /** * The timestamp the webhook was created at * @type {number} @@ -262,7 +313,17 @@ class Webhook { } static applyToClass(structure) { - for (const prop of ['send', 'sendSlackMessage', 'edit', 'delete', 'createdTimestamp', 'createdAt', 'url']) { + for (const prop of [ + 'send', + 'sendSlackMessage', + 'edit', + 'editMessage', + 'delete', + 'deleteMessage', + 'createdTimestamp', + 'createdAt', + 'url', + ]) { Object.defineProperty(structure.prototype, prop, Object.getOwnPropertyDescriptor(Webhook.prototype, prop)); } } diff --git a/typings/index.d.ts b/typings/index.d.ts index dbe0877abc58..df894f6c3d90 100644 --- a/typings/index.d.ts +++ b/typings/index.d.ts @@ -1772,6 +1772,34 @@ declare module 'discord.js' { public client: this; public options: WebhookClientOptions; public token: string; + public editMessage( + message: MessageResolvable, + content: APIMessageContentResolvable | APIMessage | MessageEmbed | MessageEmbed[], + options?: WebhookEditMessageOptions, + ): Promise; + public editMessage( + message: MessageResolvable, + options: WebhookEditMessageOptions, + ): Promise; + public send( + content: APIMessageContentResolvable | (WebhookMessageOptions & { split?: false }) | MessageAdditions, + ): Promise; + public send(options: WebhookMessageOptions & { split: true | SplitOptions }): Promise; + public send( + options: WebhookMessageOptions | APIMessage, + ): Promise; + public send( + content: StringResolvable, + options: (WebhookMessageOptions & { split?: false }) | MessageAdditions, + ): Promise; + public send( + content: StringResolvable, + options: WebhookMessageOptions & { split: true | SplitOptions }, + ): Promise; + public send( + content: StringResolvable, + options: WebhookMessageOptions, + ): Promise; } export class WebSocketManager extends EventEmitter { @@ -2096,7 +2124,17 @@ declare module 'discord.js' { readonly createdTimestamp: number; readonly url: string; delete(reason?: string): Promise; + deleteMessage(message: MessageResolvable): Promise; edit(options: WebhookEditData): Promise; + editMessage( + message: MessageResolvable, + content: APIMessageContentResolvable | APIMessage | MessageEmbed | MessageEmbed[], + options?: WebhookEditMessageOptions, + ): Promise; + editMessage( + message: MessageResolvable, + options: WebhookEditMessageOptions, + ): Promise; send( content: APIMessageContentResolvable | (WebhookMessageOptions & { split?: false }) | MessageAdditions, ): Promise; @@ -3339,17 +3377,9 @@ declare module 'discord.js' { reason?: string; } - interface WebhookMessageOptions { - username?: string; - avatarURL?: string; - tts?: boolean; - nonce?: string; - embeds?: (MessageEmbed | object)[]; - allowedMentions?: MessageMentionOptions; - files?: (FileOptions | BufferResolvable | Stream | MessageAttachment)[]; - code?: string | boolean; - split?: boolean | SplitOptions; - } + type WebhookEditMessageOptions = Pick; + + type WebhookMessageOptions = Omit & { embeds?: (MessageEmbed | object)[] }; type WebhookRawMessageResponse = Omit & { author: {