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: entry-point command #10640

Open
wants to merge 18 commits into
base: main
Choose a base branch
from
Open
4 changes: 4 additions & 0 deletions packages/discord.js/src/client/actions/InteractionCreate.js
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@ const ChatInputCommandInteraction = require('../../structures/ChatInputCommandIn
const MentionableSelectMenuInteraction = require('../../structures/MentionableSelectMenuInteraction');
const MessageContextMenuCommandInteraction = require('../../structures/MessageContextMenuCommandInteraction');
const ModalSubmitInteraction = require('../../structures/ModalSubmitInteraction');
const PrimaryEntryPointCommandInteraction = require('../../structures/PrimaryEntryPointCommandInteraction');
const RoleSelectMenuInteraction = require('../../structures/RoleSelectMenuInteraction');
const StringSelectMenuInteraction = require('../../structures/StringSelectMenuInteraction');
const UserContextMenuCommandInteraction = require('../../structures/UserContextMenuCommandInteraction');
Expand Down Expand Up @@ -38,6 +39,9 @@ class InteractionCreateAction extends Action {
if (channel && !channel.isTextBased()) return;
InteractionClass = MessageContextMenuCommandInteraction;
break;
case ApplicationCommandType.PrimaryEntryPoint:
InteractionClass = PrimaryEntryPointCommandInteraction;
break;
default:
client.emit(
Events.Debug,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -261,6 +261,7 @@ class ApplicationCommandManager extends CachedManager {
dm_permission: command.dmPermission ?? command.dm_permission,
integration_types: command.integrationTypes ?? command.integration_types,
contexts: command.contexts,
handler: command.handler,
};
}
}
Expand Down
27 changes: 23 additions & 4 deletions packages/discord.js/src/structures/ApplicationCommand.js
Original file line number Diff line number Diff line change
Expand Up @@ -174,6 +174,19 @@ class ApplicationCommand extends Base {
this.contexts ??= null;
}

if ('handler' in data) {
/**
* Determines whether the interaction is handled by the app's interactions handler or by Discord.
* <info>Only available for {@link ApplicationCommandType.PrimaryEntryPoint} command
* and for apps with `EMBEDDED` flag (i.e, applications that have an Activity)
* </info>
* @type {?EntryPointCommandHandlerType}
*/
this.handler = data.handler;
} else {
this.handler ??= null;
}

if ('version' in data) {
/**
* Autoincrementing version identifier updated during substantial record changes
Expand Down Expand Up @@ -216,15 +229,20 @@ class ApplicationCommand extends Base {
* @property {string} name The name of the command, must be in all lowercase if type is
* {@link ApplicationCommandType.ChatInput}
* @property {Object<Locale, string>} [nameLocalizations] The localizations for the command name
* @property {string} description The description of the command, if type is {@link ApplicationCommandType.ChatInput}
* @property {string} description The description of the command,
* if type is {@link ApplicationCommandType.ChatInput} or {@link ApplicationCommandType.PrimaryEntryPoint}
* @property {boolean} [nsfw] Whether the command is age-restricted
* @property {Object<Locale, string>} [descriptionLocalizations] The localizations for the command description,
* if type is {@link ApplicationCommandType.ChatInput}
* if type is {@link ApplicationCommandType.ChatInput} or {@link ApplicationCommandType.PrimaryEntryPoint}
* @property {ApplicationCommandType} [type=ApplicationCommandType.ChatInput] The type of the command
* @property {ApplicationCommandOptionData[]} [options] Options for the command
* @property {?PermissionResolvable} [defaultMemberPermissions] The bitfield used to determine the default permissions
* a member needs in order to run the command
* @property {boolean} [dmPermission] Whether the command is enabled in DMs
* @property {boolean} [dmPermission] Whether the command is enabled in DMs.
* Deprecated, use {@link ApplicationCommandData#contexts} instead.
* @property {ApplicationIntegrationType[]} [integrationTypes] Installation context(s) where the command is available
* @property {InteractionContextType[]} [contexts] Interaction context(s) where the command can be used
* @property {EntryPointCommandHandlerType} [handler] Determines whether the interaction is handled by the app's
*/

/**
Expand Down Expand Up @@ -419,7 +437,8 @@ class ApplicationCommand extends Base {
this.descriptionLocalizations ?? {},
) ||
!isEqual(command.integrationTypes ?? command.integration_types ?? [], this.integrationTypes ?? []) ||
!isEqual(command.contexts ?? [], this.contexts ?? [])
!isEqual(command.contexts ?? [], this.contexts ?? []) ||
('handler' in command && command.handler !== this.handler)
) {
return false;
}
Expand Down
10 changes: 10 additions & 0 deletions packages/discord.js/src/structures/BaseInteraction.js
Original file line number Diff line number Diff line change
Expand Up @@ -218,6 +218,16 @@ class BaseInteraction extends Base {
);
}

/**
* Indicates whether this interaction is a {@link PrimaryEntryPointCommandInteraction}
* @returns{boolean}
imnaiyar marked this conversation as resolved.
Show resolved Hide resolved
*/
isPrimaryEntryPointCommand() {
return (
this.type === InteractionType.ApplicationCommand && this.commandType === ApplicationCommandType.PrimaryEntryPoint
);
}

/**
* Indicates whether this interaction is a {@link MessageComponentInteraction}
* @returns {boolean}
Expand Down
1 change: 1 addition & 0 deletions packages/discord.js/src/structures/CommandInteraction.js
Original file line number Diff line number Diff line change
Expand Up @@ -152,6 +152,7 @@ class CommandInteraction extends BaseInteraction {
editReply() {}
deleteReply() {}
followUp() {}
launchActivity() {}
showModal() {}
awaitModalSubmit() {}
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -98,6 +98,7 @@ class MessageComponentInteraction extends BaseInteraction {
followUp() {}
deferUpdate() {}
update() {}
launchActivity() {}
showModal() {}
awaitModalSubmit() {}
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -118,6 +118,7 @@ class ModalSubmitInteraction extends BaseInteraction {
followUp() {}
deferUpdate() {}
update() {}
launchActivity() {}
}

InteractionResponses.applyToClass(ModalSubmitInteraction, 'showModal');
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
'use strict';

const CommandInteraction = require('./CommandInteraction');
/**
* Represents a primary entry point command interaction.
* @extends {CommandInteraction}
*/
class PrimaryEntryPointCommandInteraction extends CommandInteraction {}

module.exports = PrimaryEntryPointCommandInteraction;
Original file line number Diff line number Diff line change
Expand Up @@ -269,6 +269,24 @@ class InteractionResponses {
: new InteractionResponse(this, this.message.interaction?.id);
}

/**
* Launches activity, if enabled
* @returns {Promise<InteractionCallbackResponse>}
*/
async launchActivity() {
if (this.deferred || this.replied) throw new DiscordjsError(ErrorCodes.InteractionAlreadyReplied);
const response = await this.client.rest.post(Routes.interactionCallback(this.id, this.token), {
body: {
type: InteractionResponseType.LaunchActivity,
},
auth: false,
query: makeURLSearchParams({ with_response: true }),
imnaiyar marked this conversation as resolved.
Show resolved Hide resolved
});
this.replied = true;

return new InteractionCallbackResponse(this.client, response);
}

/**
* Shows a modal component
* @param {ModalBuilder|ModalComponentData|APIModalInteractionResponseCallbackData} modal The modal to show
Expand Down Expand Up @@ -332,6 +350,7 @@ class InteractionResponses {
'followUp',
'deferUpdate',
'update',
'launchActivity',
'showModal',
'awaitModalSubmit',
];
Expand Down
5 changes: 5 additions & 0 deletions packages/discord.js/src/util/APITypes.js
Original file line number Diff line number Diff line change
Expand Up @@ -320,6 +320,11 @@
* @see {@link https://discord-api-types.dev/api/discord-api-types-v10/enum/EntitlementType}
*/

/**
* @external EntryPointCommandHandlerType
* @see {@link https://discord-api-types.dev/api/discord-api-types-v10/enum/EntryPointCommandHandlerType}
*/

/**
* @external ForumLayoutType
* @see {@link https://discord-api-types.dev/api/discord-api-types-v10/enum/ForumLayoutType}
Expand Down
31 changes: 28 additions & 3 deletions packages/discord.js/typings/index.d.ts
Original file line number Diff line number Diff line change
Expand Up @@ -176,6 +176,8 @@ import {
RESTAPIInteractionCallbackActivityInstanceResource,
VoiceChannelEffectSendAnimationType,
GatewayVoiceChannelEffectSendDispatchData,
EntryPointCommandHandlerType,
APIPrimaryEntryPointCommandInteractionData,
} from 'discord-api-types/v10';
import { ChildProcess } from 'node:child_process';
import { EventEmitter } from 'node:events';
Expand Down Expand Up @@ -436,6 +438,7 @@ export class ApplicationCommand<PermissionsFetchType = {}> extends Base {
public get manager(): ApplicationCommandManager;
public id: Snowflake;
public integrationTypes: ApplicationIntegrationType[] | null;
public handler: EntryPointCommandHandlerType | null;
public name: string;
public nameLocalizations: LocalizationMap | null;
public nameLocalized: string | null;
Expand Down Expand Up @@ -582,6 +585,7 @@ export abstract class CommandInteraction<Cached extends CacheType = CacheType> e
public reply(
options: string | MessagePayload | InteractionReplyOptions,
): Promise<InteractionResponse<BooleanCache<Cached>>>;
public launchActivity(): Promise<InteractionCallbackResponse>;
public showModal(
modal:
| JSONEncodable<APIModalInteractionResponseCallbackData>
Expand All @@ -601,7 +605,7 @@ export abstract class CommandInteraction<Cached extends CacheType = CacheType> e
): Promise<ModalSubmitInteraction<Cached>>;
private transformOption(
option: APIApplicationCommandOption,
resolved: APIApplicationCommandInteractionData['resolved'],
resolved: Exclude<APIApplicationCommandInteractionData, APIPrimaryEntryPointCommandInteractionData>['resolved'],
): CommandInteractionOption<Cached>;
}

Expand Down Expand Up @@ -1318,6 +1322,15 @@ export class ContextMenuCommandInteraction<Cached extends CacheType = CacheType>
private resolveContextMenuOptions(data: APIApplicationCommandInteractionData): CommandInteractionOption<Cached>[];
}

export class PrimaryEntryPointCommandInteraction<
Cached extends CacheType = CacheType,
> extends CommandInteraction<Cached> {
public commandType: ApplicationCommandType.PrimaryEntryPoint;
public inGuild(): this is PrimaryEntryPointCommandInteraction<'raw' | 'cached'>;
public inCachedGuild(): this is PrimaryEntryPointCommandInteraction<'cached'>;
public inRawGuild(): this is PrimaryEntryPointCommandInteraction<'raw'>;
}

/** @internal */
export interface ResolvedFile {
data: Buffer;
Expand Down Expand Up @@ -1938,6 +1951,7 @@ export type Interaction<Cached extends CacheType = CacheType> =
| ChatInputCommandInteraction<Cached>
| MessageContextMenuCommandInteraction<Cached>
| UserContextMenuCommandInteraction<Cached>
| PrimaryEntryPointCommandInteraction<Cached>
| SelectMenuInteraction<Cached>
| ButtonInteraction<Cached>
| AutocompleteInteraction<Cached>
Expand Down Expand Up @@ -1986,6 +2000,7 @@ export class BaseInteraction<Cached extends CacheType = CacheType> extends Base
public isChatInputCommand(): this is ChatInputCommandInteraction<Cached>;
public isCommand(): this is CommandInteraction<Cached>;
public isContextMenuCommand(): this is ContextMenuCommandInteraction<Cached>;
public isPrimaryEntryPointCommand(): this is PrimaryEntryPointCommandInteraction<Cached>;
public isMessageComponent(): this is MessageComponentInteraction<Cached>;
public isMessageContextMenuCommand(): this is MessageContextMenuCommandInteraction<Cached>;
public isModalSubmit(): this is ModalSubmitInteraction<Cached>;
Expand Down Expand Up @@ -2362,6 +2377,7 @@ export class MessageComponentInteraction<Cached extends CacheType = CacheType> e
public update(
options: string | MessagePayload | InteractionUpdateOptions,
): Promise<InteractionResponse<BooleanCache<Cached>>>;
public launchActivity(): Promise<InteractionCallbackResponse>;
public showModal(
modal:
| JSONEncodable<APIModalInteractionResponseCallbackData>
Expand Down Expand Up @@ -2581,6 +2597,7 @@ export class ModalSubmitInteraction<Cached extends CacheType = CacheType> extend
options: InteractionDeferUpdateOptions & { withResponse: true },
): Promise<InteractionCallbackResponse>;
public deferUpdate(options?: InteractionDeferUpdateOptions): Promise<InteractionResponse<BooleanCache<Cached>>>;
public launchActivity(): Promise<InteractionCallbackResponse>;
public inGuild(): this is ModalSubmitInteraction<'raw' | 'cached'>;
public inCachedGuild(): this is ModalSubmitInteraction<'cached'>;
public inRawGuild(): this is ModalSubmitInteraction<'raw'>;
Expand Down Expand Up @@ -3562,7 +3579,7 @@ export function parseWebhookURL(url: string): WebhookClientDataIdWithToken | nul
/** @internal */
export function transformResolved<Cached extends CacheType>(
supportingData: SupportingInteractionResolvedData,
data?: APIApplicationCommandInteractionData['resolved'],
data?: Exclude<APIApplicationCommandInteractionData, APIPrimaryEntryPointCommandInteractionData>['resolved'],
): CommandInteractionResolvedData<Cached>;
export function resolveSKUId(resolvable: SKUResolvable): Snowflake | null;

Expand Down Expand Up @@ -4751,10 +4768,18 @@ export interface ChatInputApplicationCommandData extends BaseApplicationCommandD
options?: readonly ApplicationCommandOptionData[];
}

export interface PrimaryEntryPointCommandData extends BaseApplicationCommandData {
description?: string;
descriptionLocalizations?: LocalizationMap;
type: ApplicationCommandType.PrimaryEntryPoint;
handler?: EntryPointCommandHandlerType;
}

export type ApplicationCommandData =
| UserApplicationCommandData
| MessageApplicationCommandData
| ChatInputApplicationCommandData;
| ChatInputApplicationCommandData
| PrimaryEntryPointCommandData;

export interface ApplicationCommandChannelOptionData extends BaseApplicationCommandOptionsData {
type: CommandOptionChannelResolvableType;
Expand Down
Loading