Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat(InteractionResponses)!: support with_response query parameter #10499

Merged
merged 19 commits into from
Nov 28, 2024
Merged
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 3 additions & 0 deletions packages/discord.js/src/index.js
Original file line number Diff line number Diff line change
@@ -143,6 +143,9 @@ exports.GuildScheduledEvent = require('./structures/GuildScheduledEvent').GuildS
exports.GuildTemplate = require('./structures/GuildTemplate');
exports.Integration = require('./structures/Integration');
exports.IntegrationApplication = require('./structures/IntegrationApplication');
exports.InteractionCallback = require('./structures/InteractionCallback');
exports.InteractionCallbackResource = require('./structures/InteractionCallbackResource');
exports.InteractionCallbackResponse = require('./structures/InteractionCallbackResponse');
exports.BaseInteraction = require('./structures/BaseInteraction');
exports.InteractionCollector = require('./structures/InteractionCollector');
exports.InteractionResponse = require('./structures/InteractionResponse');
74 changes: 74 additions & 0 deletions packages/discord.js/src/structures/InteractionCallback.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,74 @@
'use strict';

const { DiscordSnowflake } = require('@sapphire/snowflake');

/**
* Represents an interaction callback response from Discord
*/
class InteractionCallback {
constructor(client, data) {
/**
* The client that instantiated this.
* @name InteractionCallback#client
* @type {Client}
* @readonly
*/
Object.defineProperty(this, 'client', { value: client });

/**
* The id of the original interaction response
* @type {Snowflake}
*/
this.id = data.id;

/**
* The type of the original interaction
* @type {InteractionType}
*/
this.type = data.type;

/**
* The instance id of the Activity if one was launched or joined
* @type {?string}
*/
this.activityInstanceId = data.activity_instance_id ?? null;

/**
* The id of the message that was created by the interaction
* @type {?Snowflake}
*/
this.responseMessageId = data.response_message_id ?? null;

/**
* Whether the message is in a loading state
* @type {?boolean}
*/
this.responseMessageLoading = data.response_message_loading ?? null;

/**
* Whether the response message was ephemeral
* @type {?boolean}
*/
this.responseMessageEphemeral = data.response_message_ephemeral ?? null;
}

/**
* The timestamp the original interaction was created at
* @type {number}
* @readonly
*/
get createdTimestamp() {
return DiscordSnowflake.timestampFrom(this.id);
}

/**
* The time the original interaction was created at
* @type {Date}
* @readonly
*/
get createdAt() {
return new Date(this.createdTimestamp);
}
}

module.exports = InteractionCallback;
Original file line number Diff line number Diff line change
@@ -0,0 +1,52 @@
'use strict';

const { lazy } = require('@discordjs/util');

const getMessage = lazy(() => require('./Message').Message);

/**
* Represents the resource that was created by the interaction response.
*/
class InteractionCallbackResource {
constructor(client, data) {
/**
* The client that instantiated this
* @name InteractionCallbackResource#client
* @type {Client}
* @readonly
*/
Object.defineProperty(this, 'client', { value: client });

/**
* The interaction callback type
* @type {InteractionResponseType}
*/
this.type = data.type;

/**
* The Activity launched by an interaction
* @typedef {Object} ActivityInstance
* @property {string} id The instance id of the Activity
*/

/**
* Represents the Activity launched by this interaction
* @type {?ActivityInstance}
*/
this.activityInstance = data.activity_instance ?? null;

if ('message' in data) {
/**
* The message created by the interaction
* @type {?Message}
*/
this.message =
this.client.channels.cache.get(data.message.channel_id)?.messages._add(data.message) ??
new (getMessage())(client, data.message);
} else {
this.message = null;
}
}
}

module.exports = InteractionCallbackResource;
Original file line number Diff line number Diff line change
@@ -0,0 +1,33 @@
'use strict';

const InteractionCallback = require('./InteractionCallback');
const InteractionCallbackResource = require('./InteractionCallbackResource');

/**
* Represents an interaction's response
*/
class InteractionCallbackResponse {
constructor(client, data) {
/**
* The client that instantiated this
* @name InteractionCallbackResponse#client
* @type {Client}
* @readonly
*/
Object.defineProperty(this, 'client', { value: client });

/**
* The interaction object associated with the interaction callback response
* @type {InteractionCallback}
*/
this.interaction = new InteractionCallback(client, data.interaction);

/**
* The resource that was created by the interaction response
* @type {?InteractionCallbackResource}
*/
this.resource = data.resource ? new InteractionCallbackResource(client, data.resource) : null;
}
}

module.exports = InteractionCallbackResponse;
Original file line number Diff line number Diff line change
@@ -1,8 +1,10 @@
'use strict';

const { makeURLSearchParams } = require('@discordjs/rest');
const { isJSONEncodable } = require('@discordjs/util');
const { InteractionResponseType, MessageFlags, Routes, InteractionType } = require('discord-api-types/v10');
const { DiscordjsError, ErrorCodes } = require('../../errors');
const InteractionCallbackResponse = require('../InteractionCallbackResponse');
const InteractionCollector = require('../InteractionCollector');
const InteractionResponse = require('../InteractionResponse');
const MessagePayload = require('../MessagePayload');
@@ -23,21 +25,21 @@ class InteractionResponses {
* Options for deferring the reply to an {@link BaseInteraction}.
* @typedef {Object} InteractionDeferReplyOptions
* @property {MessageFlagsResolvable} [flags] Flags for the reply.
* @property {boolean} [withResponse] Whether to return an {@link InteractionCallbackResponse} as the response
* <info>Only `MessageFlags.Ephemeral` can be set.</info>
* @property {boolean} [fetchReply] Whether to fetch the reply
*/

/**
* Options for deferring and updating the reply to a {@link MessageComponentInteraction}.
* @typedef {Object} InteractionDeferUpdateOptions
* @property {boolean} [fetchReply] Whether to fetch the reply
* @property {boolean} [withResponse] Whether to return an {@link InteractionCallbackResponse} as the response
*/

/**
* Options for a reply to a {@link BaseInteraction}.
* @typedef {BaseMessageOptionsWithPoll} InteractionReplyOptions
* @property {boolean} [tts=false] Whether the message should be spoken aloud
* @property {boolean} [fetchReply] Whether to fetch the reply
* @property {boolean} [withResponse] Whether to return an {@link InteractionCallbackResponse} as the response
* @property {MessageFlagsResolvable} [flags] Which flags to set for the message.
* <info>Only `MessageFlags.Ephemeral`, `MessageFlags.SuppressEmbeds`, and `MessageFlags.SuppressNotifications`
* can be set.</info>
@@ -46,13 +48,19 @@ class InteractionResponses {
/**
* Options for updating the message received from a {@link MessageComponentInteraction}.
* @typedef {MessageEditOptions} InteractionUpdateOptions
* @property {boolean} [fetchReply] Whether to fetch the reply
* @property {boolean} [withResponse] Whether to return an {@link InteractionCallbackResponse} as the response
*/

/**
* Options for showing a modal in response to a {@link BaseInteraction}
* @typedef {Object} ShowModalOptions
* @property {boolean} [withResponse] Whether to return an {@link InteractionCallbackResponse} as the response
*/

/**
* Defers the reply to this interaction.
* @param {InteractionDeferReplyOptions} [options] Options for deferring the reply to this interaction
* @returns {Promise<Message|InteractionResponse>}
* @returns {Promise<InteractionResponse|InteractionCallbackResponse>}
* @example
* // Defer the reply to this interaction
* interaction.deferReply()
@@ -67,30 +75,34 @@ class InteractionResponses {
async deferReply(options = {}) {
if (this.deferred || this.replied) throw new DiscordjsError(ErrorCodes.InteractionAlreadyReplied);

await this.client.rest.post(Routes.interactionCallback(this.id, this.token), {
const response = await this.client.rest.post(Routes.interactionCallback(this.id, this.token), {
body: {
type: InteractionResponseType.DeferredChannelMessageWithSource,
data: {
flags: options.flags,
},
},
auth: false,
query: makeURLSearchParams({ with_response: options.withResponse ?? false }),
});

this.deferred = true;
this.ephemeral = Boolean(options.flags & MessageFlags.Ephemeral);
return options.fetchReply ? this.fetchReply() : new InteractionResponse(this);

return options.withResponse
? new InteractionCallbackResponse(this.client, response)
: new InteractionResponse(this);
}

/**
* Creates a reply to this interaction.
* <info>Use the `fetchReply` option to get the bot's reply message.</info>
* <info>Use the `withResponse` option to get the interaction callback response.</info>
* @param {string|MessagePayload|InteractionReplyOptions} options The options for the reply
* @returns {Promise<Message|InteractionResponse>}
* @returns {Promise<InteractionResponse|InteractionCallbackResponse>}
* @example
* // Reply to the interaction and fetch the response
* interaction.reply({ content: 'Pong!', fetchReply: true })
* .then((message) => console.log(`Reply sent with content ${message.content}`))
* interaction.reply({ content: 'Pong!', withResponse: true })
* .then((response) => console.log(`Reply sent with content ${response.resource.message.content}`))
* .catch(console.error);
* @example
* // Create an ephemeral reply with an embed
@@ -109,18 +121,22 @@ class InteractionResponses {

const { body: data, files } = await messagePayload.resolveBody().resolveFiles();

await this.client.rest.post(Routes.interactionCallback(this.id, this.token), {
const response = await this.client.rest.post(Routes.interactionCallback(this.id, this.token), {
body: {
type: InteractionResponseType.ChannelMessageWithSource,
data,
},
files,
auth: false,
query: makeURLSearchParams({ with_response: options.withResponse ?? false }),
});

this.ephemeral = Boolean(options.flags & MessageFlags.Ephemeral);
this.replied = true;
return options.fetchReply ? this.fetchReply() : new InteractionResponse(this);

return options.withResponse
? new InteractionCallbackResponse(this.client, response)
: new InteractionResponse(this);
}

/**
@@ -192,7 +208,7 @@ class InteractionResponses {
/**
* 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<Message|InteractionResponse>}
* @returns {Promise<InteractionResponse|InteractionCallbackResponse>}
* @example
* // Defer updating and reset the component's loading state
* interaction.deferUpdate()
@@ -201,21 +217,24 @@ class InteractionResponses {
*/
async deferUpdate(options = {}) {
if (this.deferred || this.replied) throw new DiscordjsError(ErrorCodes.InteractionAlreadyReplied);
await this.client.rest.post(Routes.interactionCallback(this.id, this.token), {
const response = await this.client.rest.post(Routes.interactionCallback(this.id, this.token), {
body: {
type: InteractionResponseType.DeferredMessageUpdate,
},
auth: false,
query: makeURLSearchParams({ with_response: options.withResponse ?? false }),
});
this.deferred = true;

return options.fetchReply ? this.fetchReply() : new InteractionResponse(this, this.message?.interaction?.id);
return options.withResponse
? new InteractionCallbackResponse(this.client, response)
: new InteractionResponse(this, this.message?.interaction?.id);
}

/**
* Updates the original message of the component on which the interaction was received on.
* @param {string|MessagePayload|InteractionUpdateOptions} options The options for the updated message
* @returns {Promise<Message|void>}
* @returns {Promise<InteractionResponse|InteractionCallbackResponse>}
* @example
* // Remove the components from the message
* interaction.update({
@@ -234,34 +253,41 @@ class InteractionResponses {

const { body: data, files } = await messagePayload.resolveBody().resolveFiles();

await this.client.rest.post(Routes.interactionCallback(this.id, this.token), {
const response = await this.client.rest.post(Routes.interactionCallback(this.id, this.token), {
body: {
type: InteractionResponseType.UpdateMessage,
data,
},
files,
auth: false,
query: makeURLSearchParams({ with_response: options.withResponse ?? false }),
});
this.replied = true;

return options.fetchReply ? this.fetchReply() : new InteractionResponse(this, this.message.interaction?.id);
return options.withResponse
? new InteractionCallbackResponse(this.client, response)
: new InteractionResponse(this, this.message.interaction?.id);
}

/**
* Shows a modal component
* @param {ModalBuilder|ModalComponentData|APIModalInteractionResponseCallbackData} modal The modal to show
* @returns {Promise<void>}
* @param {ShowModalOptions} [options={}] The options for sending this interaction response
* @returns {Promise<InteractionCallbackResponse|undefined>}
*/
async showModal(modal) {
async showModal(modal, options = {}) {
if (this.deferred || this.replied) throw new DiscordjsError(ErrorCodes.InteractionAlreadyReplied);
await this.client.rest.post(Routes.interactionCallback(this.id, this.token), {
const response = await this.client.rest.post(Routes.interactionCallback(this.id, this.token), {
body: {
type: InteractionResponseType.Modal,
data: isJSONEncodable(modal) ? modal.toJSON() : this.client.options.jsonTransformer(modal),
},
auth: false,
query: makeURLSearchParams({ with_response: options.withResponse ?? false }),
});
this.replied = true;

return options.withResponse ? new InteractionCallbackResponse(this.client, response) : undefined;
}

/**
93 changes: 72 additions & 21 deletions packages/discord.js/typings/index.d.ts
Original file line number Diff line number Diff line change
@@ -168,6 +168,11 @@ import {
SubscriptionStatus,
GatewaySendPayload,
GatewayDispatchPayload,
RESTPostAPIInteractionCallbackWithResponseResult,
RESTAPIInteractionCallbackObject,
RESTAPIInteractionCallbackResourceObject,
InteractionResponseType,
RESTAPIInteractionCallbackActivityInstanceResource,
VoiceChannelEffectSendAnimationType,
GatewayVoiceChannelEffectSendDispatchData,
} from 'discord-api-types/v10';
@@ -563,16 +568,16 @@ export abstract class CommandInteraction<Cached extends CacheType = CacheType> e
public inCachedGuild(): this is CommandInteraction<'cached'>;
public inRawGuild(): this is CommandInteraction<'raw'>;
public deferReply(
options: InteractionDeferReplyOptions & { fetchReply: true },
): Promise<Message<BooleanCache<Cached>>>;
options: InteractionDeferReplyOptions & { withResponse: true },
): Promise<InteractionCallbackResponse>;
public deferReply(options?: InteractionDeferReplyOptions): Promise<InteractionResponse<BooleanCache<Cached>>>;
public deleteReply(message?: MessageResolvable | '@original'): Promise<void>;
public editReply(
options: string | MessagePayload | InteractionEditReplyOptions,
): Promise<Message<BooleanCache<Cached>>>;
public fetchReply(message?: Snowflake | '@original'): Promise<Message<BooleanCache<Cached>>>;
public followUp(options: string | MessagePayload | InteractionReplyOptions): Promise<Message<BooleanCache<Cached>>>;
public reply(options: InteractionReplyOptions & { fetchReply: true }): Promise<Message<BooleanCache<Cached>>>;
public reply(options: InteractionReplyOptions & { withResponse: true }): Promise<InteractionCallbackResponse>;
public reply(
options: string | MessagePayload | InteractionReplyOptions,
): Promise<InteractionResponse<BooleanCache<Cached>>>;
@@ -581,7 +586,15 @@ export abstract class CommandInteraction<Cached extends CacheType = CacheType> e
| JSONEncodable<APIModalInteractionResponseCallbackData>
| ModalComponentData
| APIModalInteractionResponseCallbackData,
): Promise<void>;
options: ShowModalOptions & { withResponse: true },
): Promise<InteractionCallbackResponse>;
public showModal(
modal:
| JSONEncodable<APIModalInteractionResponseCallbackData>
| ModalComponentData
| APIModalInteractionResponseCallbackData,
options?: ShowModalOptions,
): Promise<undefined>;
public awaitModalSubmit(
options: AwaitModalSubmitOptions<ModalSubmitInteraction>,
): Promise<ModalSubmitInteraction<Cached>>;
@@ -1982,6 +1995,33 @@ export class BaseInteraction<Cached extends CacheType = CacheType> extends Base
public isRepliable(): this is RepliableInteraction<Cached>;
}

export class InteractionCallback {
private constructor(client: Client<true>, data: RESTAPIInteractionCallbackObject);
public activityInstanceId: string | null;
public readonly client: Client<true>;
public get createdAt(): Date;
public get createdTimestamp(): number;
public id: Snowflake;
public responseMessageEphemeral: boolean | null;
public responseMessageId: Snowflake | null;
public responseMessageLoading: boolean | null;
public type: InteractionType;
}

export class InteractionCallbackResponse {
private constructor(client: Client<true>, data: RESTPostAPIInteractionCallbackWithResponseResult);
public readonly client: Client<true>;
public interaction: InteractionCallback;
public resource: InteractionCallbackResource | null;
}

export class InteractionCallbackResource {
private constructor(client: Client<true>, data: RESTAPIInteractionCallbackResourceObject);
public activityInstance: RESTAPIInteractionCallbackActivityInstanceResource | null;
public message: Message | null;
public type: InteractionResponseType;
}

export class InteractionCollector<Interaction extends CollectedInteraction> extends Collector<
Snowflake,
Interaction,
@@ -2297,24 +2337,24 @@ export class MessageComponentInteraction<Cached extends CacheType = CacheType> e
public inCachedGuild(): this is MessageComponentInteraction<'cached'>;
public inRawGuild(): this is MessageComponentInteraction<'raw'>;
public deferReply(
options: InteractionDeferReplyOptions & { fetchReply: true },
): Promise<Message<BooleanCache<Cached>>>;
options: InteractionDeferReplyOptions & { withResponse: true },
): Promise<InteractionCallbackResponse>;
public deferReply(options?: InteractionDeferReplyOptions): Promise<InteractionResponse<BooleanCache<Cached>>>;
public deferUpdate(
options: InteractionDeferUpdateOptions & { fetchReply: true },
): Promise<Message<BooleanCache<Cached>>>;
options: InteractionDeferUpdateOptions & { withResponse: true },
): Promise<InteractionCallbackResponse>;
public deferUpdate(options?: InteractionDeferUpdateOptions): Promise<InteractionResponse<BooleanCache<Cached>>>;
public deleteReply(message?: MessageResolvable | '@original'): Promise<void>;
public editReply(
options: string | MessagePayload | InteractionEditReplyOptions,
): Promise<Message<BooleanCache<Cached>>>;
public fetchReply(message?: Snowflake | '@original'): Promise<Message<BooleanCache<Cached>>>;
public followUp(options: string | MessagePayload | InteractionReplyOptions): Promise<Message<BooleanCache<Cached>>>;
public reply(options: InteractionReplyOptions & { fetchReply: true }): Promise<Message<BooleanCache<Cached>>>;
public reply(options: InteractionReplyOptions & { withResponse: true }): Promise<InteractionCallbackResponse>;
public reply(
options: string | MessagePayload | InteractionReplyOptions,
): Promise<InteractionResponse<BooleanCache<Cached>>>;
public update(options: InteractionUpdateOptions & { fetchReply: true }): Promise<Message<BooleanCache<Cached>>>;
public update(options: InteractionUpdateOptions & { withResponse: true }): Promise<InteractionCallbackResponse>;
public update(
options: string | MessagePayload | InteractionUpdateOptions,
): Promise<InteractionResponse<BooleanCache<Cached>>>;
@@ -2323,7 +2363,15 @@ export class MessageComponentInteraction<Cached extends CacheType = CacheType> e
| JSONEncodable<APIModalInteractionResponseCallbackData>
| ModalComponentData
| APIModalInteractionResponseCallbackData,
): Promise<void>;
options: ShowModalOptions & { withResponse: true },
): Promise<InteractionCallbackResponse>;
public showModal(
modal:
| JSONEncodable<APIModalInteractionResponseCallbackData>
| ModalComponentData
| APIModalInteractionResponseCallbackData,
options?: ShowModalOptions,
): Promise<undefined>;
public awaitModalSubmit(
options: AwaitModalSubmitOptions<ModalSubmitInteraction>,
): Promise<ModalSubmitInteraction<Cached>>;
@@ -2491,7 +2539,7 @@ export interface ModalMessageModalSubmitInteraction<Cached extends CacheType = C
extends ModalSubmitInteraction<Cached> {
message: Message<BooleanCache<Cached>>;
channelId: Snowflake;
update(options: InteractionUpdateOptions & { fetchReply: true }): Promise<Message>;
update(options: InteractionUpdateOptions & { withResponse: true }): Promise<InteractionCallbackResponse>;
update(
options: string | MessagePayload | InteractionUpdateOptions,
): Promise<InteractionResponse<BooleanCache<Cached>>>;
@@ -2511,7 +2559,7 @@ export class ModalSubmitInteraction<Cached extends CacheType = CacheType> extend
public message: Message<BooleanCache<Cached>> | null;
public replied: boolean;
public readonly webhook: InteractionWebhook;
public reply(options: InteractionReplyOptions & { fetchReply: true }): Promise<Message<BooleanCache<Cached>>>;
public reply(options: InteractionReplyOptions & { withResponse: true }): Promise<InteractionCallbackResponse>;
public reply(
options: string | MessagePayload | InteractionReplyOptions,
): Promise<InteractionResponse<BooleanCache<Cached>>>;
@@ -2520,14 +2568,14 @@ export class ModalSubmitInteraction<Cached extends CacheType = CacheType> extend
options: string | MessagePayload | InteractionEditReplyOptions,
): Promise<Message<BooleanCache<Cached>>>;
public deferReply(
options: InteractionDeferReplyOptions & { fetchReply: true },
): Promise<Message<BooleanCache<Cached>>>;
options: InteractionDeferReplyOptions & { withResponse: true },
): Promise<InteractionCallbackResponse>;
public deferReply(options?: InteractionDeferReplyOptions): Promise<InteractionResponse<BooleanCache<Cached>>>;
public fetchReply(message?: Snowflake | '@original'): Promise<Message<BooleanCache<Cached>>>;
public followUp(options: string | MessagePayload | InteractionReplyOptions): Promise<Message<BooleanCache<Cached>>>;
public deferUpdate(
options: InteractionDeferUpdateOptions & { fetchReply: true },
): Promise<Message<BooleanCache<Cached>>>;
options: InteractionDeferUpdateOptions & { withResponse: true },
): Promise<InteractionCallbackResponse>;
public deferUpdate(options?: InteractionDeferUpdateOptions): Promise<InteractionResponse<BooleanCache<Cached>>>;
public inGuild(): this is ModalSubmitInteraction<'raw' | 'cached'>;
public inCachedGuild(): this is ModalSubmitInteraction<'cached'>;
@@ -6147,24 +6195,23 @@ export interface InteractionDeferReplyOptions {
Extract<MessageFlagsString, 'Ephemeral' | 'SuppressEmbeds' | 'SuppressNotifications'>,
MessageFlags.Ephemeral | MessageFlags.SuppressEmbeds | MessageFlags.SuppressNotifications
>;
fetchReply?: boolean;
withResponse?: boolean;
}

export interface InteractionDeferUpdateOptions {
fetchReply?: boolean;
withResponse?: boolean;
}

export interface InteractionReplyOptions extends BaseMessageOptionsWithPoll {
tts?: boolean;
fetchReply?: boolean;
flags?: BitFieldResolvable<
Extract<MessageFlagsString, 'Ephemeral' | 'SuppressEmbeds' | 'SuppressNotifications'>,
MessageFlags.Ephemeral | MessageFlags.SuppressEmbeds | MessageFlags.SuppressNotifications
>;
}

export interface InteractionUpdateOptions extends MessageEditOptions {
fetchReply?: boolean;
withResponse?: boolean;
}

export interface InviteGenerationOptions {
@@ -6675,6 +6722,10 @@ export interface ShardingManagerOptions {
execArgv?: readonly string[];
}

export interface ShowModalOptions {
withResponse?: boolean;
}

export { Snowflake };

export type StageInstanceResolvable = StageInstance | Snowflake;
81 changes: 38 additions & 43 deletions packages/discord.js/typings/index.test-d.ts
Original file line number Diff line number Diff line change
@@ -208,6 +208,7 @@ import {
GuildScheduledEventManager,
SendableChannels,
PollData,
InteractionCallbackResponse,
} from '.';
import { expectAssignable, expectNotAssignable, expectNotType, expectType } from 'tsd';
import type { ContextMenuCommandBuilder, SlashCommandBuilder } from '@discordjs/builders';
@@ -432,7 +433,7 @@ client.on('messageCreate', async message => {
expectAssignable<Message<true>>(message);
const component = await message.awaitMessageComponent({ componentType: ComponentType.Button });
expectType<ButtonInteraction<'cached'>>(component);
expectType<Message<true>>(await component.reply({ fetchReply: true }));
expectType<InteractionCallbackResponse>(await component.reply({ withResponse: true }));

const buttonCollector = message.createMessageComponentCollector({ componentType: ComponentType.Button });
expectType<InteractionCollector<ButtonInteraction<'cached'>>>(buttonCollector);
@@ -1785,36 +1786,36 @@ client.on('interactionCreate', async interaction => {
expectType<MessageActionRowComponent>(interaction.component);
expectType<Message<true>>(interaction.message);
expectType<Guild>(interaction.guild);
expectType<Promise<Message<true>>>(interaction.reply({ content: 'a', fetchReply: true }));
expectType<Promise<Message<true>>>(interaction.deferReply({ fetchReply: true }));
expectType<Promise<InteractionCallbackResponse>>(interaction.reply({ content: 'a', withResponse: true }));
expectType<Promise<InteractionCallbackResponse>>(interaction.deferReply({ withResponse: true }));
expectType<Promise<Message<true>>>(interaction.editReply({ content: 'a' }));
expectType<Promise<Message<true>>>(interaction.fetchReply());
expectType<Promise<Message<true>>>(interaction.update({ content: 'a', fetchReply: true }));
expectType<Promise<Message<true>>>(interaction.deferUpdate({ fetchReply: true }));
expectType<Promise<InteractionCallbackResponse>>(interaction.update({ content: 'a', withResponse: true }));
expectType<Promise<InteractionCallbackResponse>>(interaction.deferUpdate({ withResponse: true }));
expectType<Promise<Message<true>>>(interaction.followUp({ content: 'a' }));
} else if (interaction.inRawGuild()) {
expectAssignable<MessageComponentInteraction>(interaction);
expectType<APIButtonComponent | APISelectMenuComponent>(interaction.component);
expectType<Message<false>>(interaction.message);
expectType<null>(interaction.guild);
expectType<Promise<Message<false>>>(interaction.reply({ content: 'a', fetchReply: true }));
expectType<Promise<Message<false>>>(interaction.deferReply({ fetchReply: true }));
expectType<Promise<InteractionCallbackResponse>>(interaction.reply({ content: 'a', withResponse: true }));
expectType<Promise<InteractionCallbackResponse>>(interaction.deferReply({ withResponse: true }));
expectType<Promise<Message<false>>>(interaction.editReply({ content: 'a' }));
expectType<Promise<Message<false>>>(interaction.fetchReply());
expectType<Promise<Message<false>>>(interaction.update({ content: 'a', fetchReply: true }));
expectType<Promise<Message<false>>>(interaction.deferUpdate({ fetchReply: true }));
expectType<Promise<InteractionCallbackResponse>>(interaction.update({ content: 'a', withResponse: true }));
expectType<Promise<InteractionCallbackResponse>>(interaction.deferUpdate({ withResponse: true }));
expectType<Promise<Message<false>>>(interaction.followUp({ content: 'a' }));
} else if (interaction.inGuild()) {
expectAssignable<MessageComponentInteraction>(interaction);
expectType<MessageActionRowComponent | APIButtonComponent | APISelectMenuComponent>(interaction.component);
expectType<Message>(interaction.message);
expectType<Guild | null>(interaction.guild);
expectType<Promise<Message>>(interaction.reply({ content: 'a', fetchReply: true }));
expectType<Promise<Message>>(interaction.deferReply({ fetchReply: true }));
expectType<Promise<InteractionCallbackResponse>>(interaction.reply({ content: 'a', withResponse: true }));
expectType<Promise<InteractionCallbackResponse>>(interaction.deferReply({ withResponse: true }));
expectType<Promise<Message>>(interaction.editReply({ content: 'a' }));
expectType<Promise<Message>>(interaction.fetchReply());
expectType<Promise<Message>>(interaction.update({ content: 'a', fetchReply: true }));
expectType<Promise<Message>>(interaction.deferUpdate({ fetchReply: true }));
expectType<Promise<InteractionCallbackResponse>>(interaction.update({ content: 'a', withResponse: true }));
expectType<Promise<InteractionCallbackResponse>>(interaction.deferUpdate({ withResponse: true }));
expectType<Promise<Message>>(interaction.followUp({ content: 'a' }));
}
}
@@ -1848,24 +1849,24 @@ client.on('interactionCreate', async interaction => {
expectAssignable<ContextMenuCommandInteraction>(interaction);
expectAssignable<Guild>(interaction.guild);
expectAssignable<CommandInteraction<'cached'>>(interaction);
expectType<Promise<Message<true>>>(interaction.reply({ content: 'a', fetchReply: true }));
expectType<Promise<Message<true>>>(interaction.deferReply({ fetchReply: true }));
expectType<Promise<InteractionCallbackResponse>>(interaction.reply({ content: 'a', withResponse: true }));
expectType<Promise<InteractionCallbackResponse>>(interaction.deferReply({ withResponse: true }));
expectType<Promise<Message<true>>>(interaction.editReply({ content: 'a' }));
expectType<Promise<Message<true>>>(interaction.fetchReply());
expectType<Promise<Message<true>>>(interaction.followUp({ content: 'a' }));
} else if (interaction.inRawGuild()) {
expectAssignable<ContextMenuCommandInteraction>(interaction);
expectType<null>(interaction.guild);
expectType<Promise<Message<false>>>(interaction.reply({ content: 'a', fetchReply: true }));
expectType<Promise<Message<false>>>(interaction.deferReply({ fetchReply: true }));
expectType<Promise<InteractionCallbackResponse>>(interaction.reply({ content: 'a', withResponse: true }));
expectType<Promise<InteractionCallbackResponse>>(interaction.deferReply({ withResponse: true }));
expectType<Promise<Message<false>>>(interaction.editReply({ content: 'a' }));
expectType<Promise<Message<false>>>(interaction.fetchReply());
expectType<Promise<Message<false>>>(interaction.followUp({ content: 'a' }));
} else if (interaction.inGuild()) {
expectAssignable<ContextMenuCommandInteraction>(interaction);
expectType<Guild | null>(interaction.guild);
expectType<Promise<Message>>(interaction.reply({ content: 'a', fetchReply: true }));
expectType<Promise<Message>>(interaction.deferReply({ fetchReply: true }));
expectType<Promise<InteractionCallbackResponse>>(interaction.reply({ content: 'a', withResponse: true }));
expectType<Promise<InteractionCallbackResponse>>(interaction.deferReply({ withResponse: true }));
expectType<Promise<Message>>(interaction.editReply({ content: 'a' }));
expectType<Promise<Message>>(interaction.fetchReply());
expectType<Promise<Message>>(interaction.followUp({ content: 'a' }));
@@ -1919,19 +1920,19 @@ client.on('interactionCreate', async interaction => {
expectType<ButtonComponent>(interaction.component);
expectType<Message<true>>(interaction.message);
expectType<Guild>(interaction.guild);
expectType<Promise<Message<true>>>(interaction.reply({ fetchReply: true }));
expectType<Promise<InteractionCallbackResponse>>(interaction.reply({ withResponse: true }));
} else if (interaction.inRawGuild()) {
expectAssignable<ButtonInteraction>(interaction);
expectType<APIButtonComponent>(interaction.component);
expectType<Message<false>>(interaction.message);
expectType<null>(interaction.guild);
expectType<Promise<Message<false>>>(interaction.reply({ fetchReply: true }));
expectType<Promise<InteractionCallbackResponse>>(interaction.reply({ withResponse: true }));
} else if (interaction.inGuild()) {
expectAssignable<ButtonInteraction>(interaction);
expectType<ButtonComponent | APIButtonComponent>(interaction.component);
expectType<Message>(interaction.message);
expectAssignable<Guild | null>(interaction.guild);
expectType<Promise<Message>>(interaction.reply({ fetchReply: true }));
expectType<Promise<InteractionCallbackResponse>>(interaction.reply({ withResponse: true }));
}
}

@@ -1947,19 +1948,19 @@ client.on('interactionCreate', async interaction => {
expectType<StringSelectMenuComponent>(interaction.component);
expectType<Message<true>>(interaction.message);
expectType<Guild>(interaction.guild);
expectType<Promise<Message<true>>>(interaction.reply({ fetchReply: true }));
expectType<Promise<InteractionCallbackResponse>>(interaction.reply({ withResponse: true }));
} else if (interaction.inRawGuild()) {
expectAssignable<StringSelectMenuInteraction>(interaction);
expectType<APIStringSelectComponent>(interaction.component);
expectType<Message<false>>(interaction.message);
expectType<null>(interaction.guild);
expectType<Promise<Message<false>>>(interaction.reply({ fetchReply: true }));
expectType<Promise<InteractionCallbackResponse>>(interaction.reply({ withResponse: true }));
} else if (interaction.inGuild()) {
expectAssignable<StringSelectMenuInteraction>(interaction);
expectType<StringSelectMenuComponent | APIStringSelectComponent>(interaction.component);
expectType<Message>(interaction.message);
expectType<Guild | null>(interaction.guild);
expectType<Promise<Message>>(interaction.reply({ fetchReply: true }));
expectType<Promise<InteractionCallbackResponse>>(interaction.reply({ withResponse: true }));
}
}

@@ -1970,21 +1971,15 @@ client.on('interactionCreate', async interaction => {
if (interaction.inRawGuild()) {
expectNotAssignable<Interaction<'cached'>>(interaction);
expectAssignable<ChatInputCommandInteraction>(interaction);
expectType<Promise<Message<false>>>(interaction.reply({ fetchReply: true }));
expectType<Promise<InteractionCallbackResponse>>(interaction.reply({ withResponse: true }));
expectType<APIInteractionDataResolvedGuildMember | null>(interaction.options.getMember('test'));

expectType<APIInteractionDataResolvedChannel>(interaction.options.getChannel('test', true));
expectType<APIRole>(interaction.options.getRole('test', true));
} else if (interaction.inCachedGuild()) {
const msg = await interaction.reply({ fetchReply: true });
const btn = await msg.awaitMessageComponent({ componentType: ComponentType.Button });

expectType<Message<true>>(msg);
expectType<ButtonInteraction<'cached'>>(btn);

expectType<GuildMember | null>(interaction.options.getMember('test'));
expectAssignable<ChatInputCommandInteraction>(interaction);
expectType<Promise<Message<true>>>(interaction.reply({ fetchReply: true }));
expectType<Promise<InteractionCallbackResponse>>(interaction.reply({ withResponse: true }));

expectType<GuildBasedChannel>(interaction.options.getChannel('test', true));
expectType<Role>(interaction.options.getRole('test', true));
@@ -2010,7 +2005,7 @@ client.on('interactionCreate', async interaction => {
// @ts-expect-error
consumeCachedCommand(interaction);
expectType<ChatInputCommandInteraction>(interaction);
expectType<Promise<Message>>(interaction.reply({ fetchReply: true }));
expectType<Promise<InteractionCallbackResponse>>(interaction.reply({ withResponse: true }));
expectType<APIInteractionDataResolvedGuildMember | GuildMember | null>(interaction.options.getMember('test'));

expectType<GuildBasedChannel | APIInteractionDataResolvedChannel>(interaction.options.getChannel('test', true));
@@ -2064,29 +2059,29 @@ client.on('interactionCreate', async interaction => {
if (interaction.inCachedGuild()) {
expectAssignable<ModalSubmitInteraction>(interaction);
expectType<Guild>(interaction.guild);
expectType<Promise<Message<true>>>(interaction.reply({ content: 'a', fetchReply: true }));
expectType<Promise<Message<true>>>(interaction.deferReply({ fetchReply: true }));
expectType<Promise<InteractionCallbackResponse>>(interaction.reply({ content: 'a', withResponse: true }));
expectType<Promise<InteractionCallbackResponse>>(interaction.deferReply({ withResponse: true }));
expectType<Promise<Message<true>>>(interaction.editReply({ content: 'a' }));
expectType<Promise<Message<true>>>(interaction.fetchReply());
expectType<Promise<Message<true>>>(interaction.deferUpdate({ fetchReply: true }));
expectType<Promise<InteractionCallbackResponse>>(interaction.deferUpdate({ withResponse: true }));
expectType<Promise<Message<true>>>(interaction.followUp({ content: 'a' }));
} else if (interaction.inRawGuild()) {
expectAssignable<ModalSubmitInteraction>(interaction);
expectType<null>(interaction.guild);
expectType<Promise<Message<false>>>(interaction.reply({ content: 'a', fetchReply: true }));
expectType<Promise<Message<false>>>(interaction.deferReply({ fetchReply: true }));
expectType<Promise<InteractionCallbackResponse>>(interaction.reply({ content: 'a', withResponse: true }));
expectType<Promise<InteractionCallbackResponse>>(interaction.deferReply({ withResponse: true }));
expectType<Promise<Message<false>>>(interaction.editReply({ content: 'a' }));
expectType<Promise<Message<false>>>(interaction.fetchReply());
expectType<Promise<Message<false>>>(interaction.deferUpdate({ fetchReply: true }));
expectType<Promise<InteractionCallbackResponse>>(interaction.deferUpdate({ withResponse: true }));
expectType<Promise<Message<false>>>(interaction.followUp({ content: 'a' }));
} else if (interaction.inGuild()) {
expectAssignable<ModalSubmitInteraction>(interaction);
expectType<Guild | null>(interaction.guild);
expectType<Promise<Message>>(interaction.reply({ content: 'a', fetchReply: true }));
expectType<Promise<Message>>(interaction.deferReply({ fetchReply: true }));
expectType<Promise<InteractionCallbackResponse>>(interaction.reply({ content: 'a', withResponse: true }));
expectType<Promise<InteractionCallbackResponse>>(interaction.deferReply({ withResponse: true }));
expectType<Promise<Message>>(interaction.editReply({ content: 'a' }));
expectType<Promise<Message>>(interaction.fetchReply());
expectType<Promise<Message>>(interaction.deferUpdate({ fetchReply: true }));
expectType<Promise<InteractionCallbackResponse>>(interaction.deferUpdate({ withResponse: true }));
expectType<Promise<Message>>(interaction.followUp({ content: 'a' }));
}
}