From 5e28ff83cbc04850077cc2f97bb2039c55b3b8ea Mon Sep 17 00:00:00 2001 From: monbrey Date: Wed, 30 Jun 2021 07:32:33 +1000 Subject: [PATCH] feat(Interactions): option to auto-fetch replies (#5831) --- src/errors/Messages.js | 1 + src/structures/MessageComponentInteraction.js | 4 +-- .../interfaces/InteractionResponses.js | 35 ++++++++++++++----- typings/index.d.ts | 24 +++++++++++-- 4 files changed, 50 insertions(+), 14 deletions(-) diff --git a/src/errors/Messages.js b/src/errors/Messages.js index 2bdec03e3b92..00290a1b632c 100644 --- a/src/errors/Messages.js +++ b/src/errors/Messages.js @@ -126,6 +126,7 @@ const Messages = { INTERACTION_ALREADY_REPLIED: 'This interaction has already been deferred or replied to.', INTERACTION_NOT_REPLIED: 'This interaction has not been deferred or replied to.', INTERACTION_EPHEMERAL_REPLIED: 'Ephemeral responses cannot be fetched or deleted.', + INTERACTION_FETCH_EPHEMERAL: 'Ephemeral responses cannot be fetched.', }; for (const [name, message] of Object.entries(Messages)) register(name, message); diff --git a/src/structures/MessageComponentInteraction.js b/src/structures/MessageComponentInteraction.js index ac28215ea263..9f72880c08f6 100644 --- a/src/structures/MessageComponentInteraction.js +++ b/src/structures/MessageComponentInteraction.js @@ -16,9 +16,9 @@ class MessageComponentInteraction extends Interaction { /** * The message to which the component was attached - * @type {?(Message|APIMessage)} + * @type {Message|APIMessage} */ - this.message = data.message ? this.channel?.messages.add(data.message) ?? data.message : null; + this.message = this.channel?.messages.add(data.message) ?? data.message; /** * The custom ID of the component which was interacted with diff --git a/src/structures/interfaces/InteractionResponses.js b/src/structures/interfaces/InteractionResponses.js index 5679f8d9acc6..c01cd4f31472 100644 --- a/src/structures/interfaces/InteractionResponses.js +++ b/src/structures/interfaces/InteractionResponses.js @@ -25,7 +25,7 @@ class InteractionResponses { /** * Defers the reply to this interaction. * @param {InteractionDeferOptions} [options] Options for deferring the reply to this interaction - * @returns {Promise} + * @returns {Promise} * @example * // Defer the reply to this interaction * interaction.defer() @@ -37,18 +37,21 @@ class InteractionResponses { * .then(console.log) * .catch(console.error); */ - async defer({ ephemeral } = {}) { + async defer(options = {}) { if (this.deferred || this.replied) throw new Error('INTERACTION_ALREADY_REPLIED'); - this.ephemeral = ephemeral ?? false; + if (options.fetchReply && options.ephemeral) throw new Error('INTERACTION_FETCH_EPHEMERAL'); + this.ephemeral = options.ephemeral ?? false; await this.client.api.interactions(this.id, this.token).callback.post({ data: { type: InteractionResponseTypes.DEFERRED_CHANNEL_MESSAGE_WITH_SOURCE, data: { - flags: ephemeral ? MessageFlags.FLAGS.EPHEMERAL : undefined, + flags: options.ephemeral ? MessageFlags.FLAGS.EPHEMERAL : undefined, }, }, }); this.deferred = true; + + return options.fetchReply ? this.fetchReply() : undefined; } /** @@ -70,6 +73,7 @@ class InteractionResponses { */ async reply(options) { if (this.deferred || this.replied) throw new Error('INTERACTION_ALREADY_REPLIED'); + if (options.fetchReply && options.ephemeral) throw new Error('INTERACTION_FETCH_EPHEMERAL'); this.ephemeral = options.ephemeral ?? false; let messagePayload; @@ -86,6 +90,8 @@ class InteractionResponses { files, }); this.replied = true; + + return options.fetchReply ? this.fetchReply() : undefined; } /** @@ -146,28 +152,34 @@ class InteractionResponses { } /** - * Defers an update to the message to which the component was attached - * @returns {Promise} + * Defers an update to the message to which the component was attached. + * @param {InteractionDeferUpdateOptions} [options] Options for deferring the update to this interaction + * @returns {Promise} * @example * // Defer updating and reset the component's loading state * interaction.deferUpdate() * .then(console.log) * .catch(console.error); */ - async deferUpdate() { + async deferUpdate(options = {}) { if (this.deferred || this.replied) throw new Error('INTERACTION_ALREADY_REPLIED'); + if (options.fetchReply && new MessageFlags(this.message.flags).has(MessageFlags.FLAGS.EPHEMERAL)) { + throw new Error('INTERACTION_FETCH_EPHEMERAL'); + } await this.client.api.interactions(this.id, this.token).callback.post({ data: { type: InteractionResponseTypes.DEFERRED_MESSAGE_UPDATE, }, }); this.deferred = true; + + return options.fetchReply ? this.fetchReply() : undefined; } /** - * Updates the original message whose button was pressed + * Updates the original message whose button was pressed. * @param {string|MessagePayload|WebhookEditMessageOptions} options The options for the reply - * @returns {Promise} + * @returns {Promise} * @example * // Remove the components from the message * interaction.update({ @@ -179,6 +191,9 @@ class InteractionResponses { */ async update(options) { if (this.deferred || this.replied) throw new Error('INTERACTION_ALREADY_REPLIED'); + if (options.fetchReply && new MessageFlags(this.message.flags).has(MessageFlags.FLAGS.EPHEMERAL)) { + throw new Error('INTERACTION_FETCH_EPHEMERAL'); + } let messagePayload; if (options instanceof MessagePayload) messagePayload = options; @@ -194,6 +209,8 @@ class InteractionResponses { files, }); this.replied = true; + + return options.fetchReply ? this.fetchReply() : undefined; } static applyToClass(structure, ignore = []) { diff --git a/typings/index.d.ts b/typings/index.d.ts index 95637e25ee64..eb0f3044b32e 100644 --- a/typings/index.d.ts +++ b/typings/index.d.ts @@ -558,11 +558,14 @@ declare module 'discord.js' { public options: Collection; public replied: boolean; public webhook: InteractionWebhook; + public defer(options?: InteractionDeferOptions & { fetchReply: true }): Promise; public defer(options?: InteractionDeferOptions): Promise; public deleteReply(): Promise; public editReply(options: string | MessagePayload | WebhookEditMessageOptions): Promise; public fetchReply(): Promise; - public followUp(options: string | MessagePayload | InteractionReplyOptions): Promise; + public reply( + options: string | MessagePayload | (InteractionReplyOptions & { fetchReply: true }), + ): Promise; public reply(options: string | MessagePayload | InteractionReplyOptions): Promise; private transformOption(option: unknown, resolved: unknown): CommandInteractionOption; private _createOptionsCollection(options: unknown, resolved: unknown): Collection; @@ -1417,14 +1420,23 @@ declare module 'discord.js' { public message: Message | APIMessage; public replied: boolean; public webhook: InteractionWebhook; + public defer(options?: InteractionDeferOptions & { fetchReply: true }): Promise; public defer(options?: InteractionDeferOptions): Promise; - public deferUpdate(): Promise; + public deferUpdate(options?: InteractionDeferUpdateOptions & { fetchReply: true }): Promise; + public deferUpdate(options?: InteractionDeferUpdateOptions): Promise; public deleteReply(): Promise; public editReply(options: string | MessagePayload | WebhookEditMessageOptions): Promise; public fetchReply(): Promise; public followUp(options: string | MessagePayload | InteractionReplyOptions): Promise; + public reply( + options: string | MessagePayload | (InteractionReplyOptions & { fetchReply: true }), + ): Promise; public reply(options: string | MessagePayload | InteractionReplyOptions): Promise; - public update(content: string | MessagePayload | WebhookEditMessageOptions): Promise; + public update( + content: string | MessagePayload | (InteractionUpdateOptions & { fetchReply: true }), + ): Promise; + public update(content: string | MessagePayload | InteractionUpdateOptions): Promise; + public static resolveType(type: MessageComponentTypeResolvable): MessageComponentType; } @@ -3609,16 +3621,22 @@ declare module 'discord.js' { interface InteractionDeferOptions { ephemeral?: boolean; + fetchReply?: boolean; } + interface InteractionDeferUpdateOptions extends Omit {} + interface InteractionReplyOptions extends Omit { ephemeral?: boolean; + fetchReply?: boolean; } type InteractionResponseType = keyof typeof InteractionResponseTypes; type InteractionType = keyof typeof InteractionTypes; + interface InteractionUpdateOptions extends Omit {} + type IntentsString = | 'GUILDS' | 'GUILD_MEMBERS'