Skip to content

Commit

Permalink
feat: entry point command
Browse files Browse the repository at this point in the history
  • Loading branch information
imnaiyar committed Jan 28, 2025
1 parent 6df42db commit 028aa55
Show file tree
Hide file tree
Showing 12 changed files with 247 additions and 21 deletions.
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/ChatInputComma
const { MentionableSelectMenuInteraction } = require('../../structures/MentionableSelectMenuInteraction.js');
const { MessageContextMenuCommandInteraction } = require('../../structures/MessageContextMenuCommandInteraction.js');
const { ModalSubmitInteraction } = require('../../structures/ModalSubmitInteraction.js');
const { PrimaryEntryPointCommandInteraction } = require('../../structures/PrimaryEntryPointCommandInteraction.js');
const { RoleSelectMenuInteraction } = require('../../structures/RoleSelectMenuInteraction.js');
const { StringSelectMenuInteraction } = require('../../structures/StringSelectMenuInteraction.js');
const { UserContextMenuCommandInteraction } = require('../../structures/UserContextMenuCommandInteraction.js');
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
2 changes: 2 additions & 0 deletions packages/discord.js/src/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -196,6 +196,8 @@ exports.PartialGroupDMChannel = require('./structures/PartialGroupDMChannel.js')
exports.PermissionOverwrites = require('./structures/PermissionOverwrites.js').PermissionOverwrites;
exports.Poll = require('./structures/Poll.js').Poll;
exports.PollAnswer = require('./structures/PollAnswer.js').PollAnswer;
exports.PrimaryEntryPointCommandInteraction =
require('./structures/PrimaryEntryPointCommandInteraction.js').PrimaryEntryPointCommandInteraction;
exports.Presence = require('./structures/Presence.js').Presence;
exports.ReactionCollector = require('./structures/ReactionCollector.js').ReactionCollector;
exports.ReactionEmoji = require('./structures/ReactionEmoji.js').ReactionEmoji;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -282,6 +282,7 @@ class ApplicationCommandManager extends CachedManager {
default_member_permissions,
integration_types: command.integrationTypes ?? command.integration_types,
contexts: command.contexts,
handler: command.handler,
};
}
}
Expand Down
29 changes: 26 additions & 3 deletions packages/discord.js/src/structures/ApplicationCommand.js
Original file line number Diff line number Diff line change
Expand Up @@ -162,6 +162,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 {@link ApplicationFlags.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 @@ -204,14 +217,18 @@ 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 {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 @@ -395,7 +412,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 Expand Up @@ -595,3 +613,8 @@ exports.ApplicationCommand = ApplicationCommand;
* @external ApplicationCommandOptionAllowedChannelTypes
* @see {@link https://discord.js.org/docs/packages/builders/stable/ApplicationCommandOptionAllowedChannelTypes:TypeAlias}
*/

/**
* @external EntryPointCommandHandlerType
* @see {@link https://discord-api-types.dev/api/discord-api-types-v10/enum/EntryPointCommandHandlerType}
*/
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}
*/
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');

Check failure on line 3 in packages/discord.js/src/structures/PrimaryEntryPointCommandInteraction.js

View workflow job for this annotation

GitHub Actions / Tests

Missing file extension "js" for "./CommandInteraction"
/**
* Represents a primary entry point command interaction.
* @extends {CommandInteraction}
*/
class PrimaryEntryPointCommandInteraction extends CommandInteraction {}

exports.PrimaryEntryPointCommandInteraction = PrimaryEntryPointCommandInteraction;
Original file line number Diff line number Diff line change
Expand Up @@ -51,6 +51,12 @@ class InteractionResponses {
* @property {boolean} [withResponse] Whether to return an {@link InteractionCallbackResponse} as the response
*/

/**
* Options for launching activity in response to a {@link BaseInteraction}
* @typedef {Object} LaunchActivityOptions
* @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
Expand Down Expand Up @@ -265,6 +271,25 @@ class InteractionResponses {
return options.withResponse ? new InteractionCallbackResponse(this.client, response) : undefined;
}

/**
* Launches activity, if enabled
* @param {LaunchActivityOptions} [options={}] Options for launching the activity
* @returns {Promise<InteractionCallbackResponse|undefined>}
*/
async launchActivity({ withResponse } = {}) {
if (this.deferred || this.replied) throw new DiscordjsError(ErrorCodes.InteractionAlreadyReplied);
const response = await this.client.rest.post(Routes.interactionCallback(this.id, this.token), {
query: makeURLSearchParams({ with_response: withResponse ?? false }),
body: {
type: InteractionResponseType.LaunchActivity,
},
auth: false,
});
this.replied = true;

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

/**
* Shows a modal component
* @param {ModalBuilder|ModalComponentData|APIModalInteractionResponseCallbackData} modal The modal to show
Expand Down Expand Up @@ -328,6 +353,7 @@ class InteractionResponses {
'followUp',
'deferUpdate',
'update',
'launchActivity',
'showModal',
'awaitModalSubmit',
];
Expand Down
71 changes: 53 additions & 18 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 { Stream } from 'node:stream';
Expand Down Expand Up @@ -438,6 +440,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 @@ -540,23 +543,6 @@ export type BooleanCache<Cached extends CacheType> = Cached extends 'cached' ? t
export abstract class CommandInteraction<Cached extends CacheType = CacheType> extends BaseInteraction<Cached> {
public type: InteractionType.ApplicationCommand;
public get command(): ApplicationCommand | ApplicationCommand<{ guild: GuildResolvable }> | null;
public options: Omit<
CommandInteractionOptionResolver<Cached>,
| 'getMessage'
| 'getFocused'
| 'getMentionable'
| 'getRole'
| 'getUser'
| 'getMember'
| 'getAttachment'
| 'getNumber'
| 'getInteger'
| 'getString'
| 'getChannel'
| 'getBoolean'
| 'getSubcommandGroup'
| 'getSubcommand'
>;
public channelId: Snowflake;
public commandId: Snowflake;
public commandName: string;
Expand Down Expand Up @@ -585,6 +571,9 @@ export abstract class CommandInteraction<Cached extends CacheType = CacheType> e
public reply(
options: string | MessagePayload | InteractionReplyOptions,
): Promise<InteractionCallbackResponse | undefined>;
public launchActivity(options: LaunchActivityOptions & { withResponse: true }): Promise<InteractionCallbackResponse>;
public launchActivity(options?: LaunchActivityOptions & { withResponse?: false }): Promise<undefined>;
public launchActivity(options?: LaunchActivityOptions): Promise<InteractionCallbackResponse | undefined>;
public showModal(
modal:
| JSONEncodable<APIModalInteractionResponseCallbackData>
Expand Down Expand Up @@ -1259,6 +1248,23 @@ export class CommandInteractionOptionResolver<Cached extends CacheType = CacheTy
}

export class ContextMenuCommandInteraction<Cached extends CacheType = CacheType> extends CommandInteraction<Cached> {
public options: Omit<
CommandInteractionOptionResolver<Cached>,
| 'getMessage'
| 'getFocused'
| 'getMentionable'
| 'getRole'
| 'getUser'
| 'getMember'
| 'getAttachment'
| 'getNumber'
| 'getInteger'
| 'getString'
| 'getChannel'
| 'getBoolean'
| 'getSubcommandGroup'
| 'getSubcommand'
>;
public commandType: ApplicationCommandType.Message | ApplicationCommandType.User;
public targetId: Snowflake;
public inGuild(): this is ContextMenuCommandInteraction<'raw' | 'cached'>;
Expand All @@ -1267,6 +1273,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'>;
}

// tslint:disable-next-line no-empty-interface
export interface DMChannel
extends Omit<
Expand Down Expand Up @@ -1880,6 +1895,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 @@ -1928,6 +1944,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 @@ -2288,6 +2305,9 @@ export class MessageComponentInteraction<Cached extends CacheType = CacheType> e
public update(
options: string | MessagePayload | InteractionUpdateOptions,
): Promise<InteractionCallbackResponse | undefined>;
public launchActivity(options: LaunchActivityOptions & { withResponse: true }): Promise<InteractionCallbackResponse>;
public launchActivity(options?: LaunchActivityOptions & { withResponse?: false }): Promise<undefined>;
public launchActivity(options?: LaunchActivityOptions): Promise<InteractionCallbackResponse | undefined>;
public showModal(
modal:
| JSONEncodable<APIModalInteractionResponseCallbackData>
Expand Down Expand Up @@ -2516,6 +2536,9 @@ export class ModalSubmitInteraction<Cached extends CacheType = CacheType> extend
): Promise<InteractionCallbackResponse>;
public deferUpdate(options?: InteractionDeferUpdateOptions & { withResponse: false }): Promise<undefined>;
public deferUpdate(options?: InteractionDeferUpdateOptions): Promise<InteractionCallbackResponse | undefined>;
public launchActivity(options: LaunchActivityOptions & { withResponse: true }): Promise<InteractionCallbackResponse>;
public launchActivity(options?: LaunchActivityOptions & { withResponse?: false }): Promise<undefined>;
public launchActivity(options?: LaunchActivityOptions): Promise<InteractionCallbackResponse | undefined>;
public inGuild(): this is ModalSubmitInteraction<'raw' | 'cached'>;
public inCachedGuild(): this is ModalSubmitInteraction<'cached'>;
public inRawGuild(): this is ModalSubmitInteraction<'raw'>;
Expand Down Expand Up @@ -4636,10 +4659,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 Expand Up @@ -6644,6 +6675,10 @@ export interface ShowModalOptions {
withResponse?: boolean;
}

export interface LaunchActivityOptions {
withResponse?: boolean;
}

export { Snowflake };

export type StageInstanceResolvable = StageInstance | Snowflake;
Expand Down
Loading

0 comments on commit 028aa55

Please sign in to comment.