Skip to content

Commit

Permalink
feat: support for user-installable apps
Browse files Browse the repository at this point in the history
  • Loading branch information
Snazzah committed Mar 29, 2024
1 parent 4085c88 commit 9210885
Show file tree
Hide file tree
Showing 4 changed files with 136 additions and 9 deletions.
37 changes: 33 additions & 4 deletions src/command.ts
Original file line number Diff line number Diff line change
@@ -1,6 +1,8 @@
import {
ApplicationCommandOption,
ApplicationCommandType,
ApplicationIntegrationType,
InteractionContextType,
PartialApplicationCommand,
PermissionNames
} from './constants';
Expand Down Expand Up @@ -38,8 +40,15 @@ export class SlashCommand<T = any> {
readonly deferEphemeral: boolean;
/** Whether this command is age-restricted. */
readonly nsfw: boolean;
/** Whether to enable this command in direct messages. */
/**
* Whether to enable this command in direct messages.
* @deprecated Use {@link SlashCommand#contexts} instead.
*/
readonly dmPermission: boolean;
/** The contexts where this command is available. */
readonly integrationTypes: ApplicationIntegrationType[];
/** The contexts where this command can be used. */
readonly contexts: InteractionContextType[];
/**
* The file path of the command.
* Used for refreshing the require cache.
Expand Down Expand Up @@ -81,7 +90,14 @@ export class SlashCommand<T = any> {
this.throttling = opts.throttling;
this.unknown = opts.unknown || false;
this.deferEphemeral = opts.deferEphemeral || false;
this.dmPermission = typeof opts.dmPermission === 'boolean' ? opts.dmPermission : true;
this.contexts = opts.contexts || [];
this.integrationTypes = opts.integrationTypes || [ApplicationIntegrationType.GUILD_INSTALL];
this.dmPermission =
typeof opts.dmPermission === 'boolean'
? opts.dmPermission
: this.contexts.length !== 0
? this.contexts.includes(InteractionContextType.BOT_DM)
: true;
}

/**
Expand All @@ -98,7 +114,13 @@ export class SlashCommand<T = any> {
name_localizations: this.nameLocalizations || null,
description: this.description || '',
description_localizations: this.descriptionLocalizations || null,
...(global ? { dm_permission: this.dmPermission } : {}),
...(global
? {
dm_permission: this.dmPermission,
contexts: this.contexts.length !== 0 ? this.contexts : null,
integration_types: this.integrationTypes
}
: {}),
nsfw: this.nsfw,
...(this.type === ApplicationCommandType.CHAT_INPUT
? {
Expand Down Expand Up @@ -344,10 +366,17 @@ export interface SlashCommandOptions {
unknown?: boolean;
/** Whether responses from this command should defer ephemeral messages. */
deferEphemeral?: boolean;
/** Whether to enable this command in direct messages. `true` by default. */
/**
* Whether to enable this command in direct messages. `true` by default.
* @deprecated Use {@link SlashCommandOptions#contexts} instead.
*/
dmPermission?: boolean;
/** Whether this command is age-restricted. `false` by default. */
nsfw?: boolean;
/** The contexts where this command is available. */
integrationTypes?: ApplicationIntegrationType[];
/** The contexts where this command can be used. */
contexts?: InteractionContextType[];
}

/** The throttling options for a {@link SlashCommand}. */
Expand Down
35 changes: 34 additions & 1 deletion src/constants.ts
Original file line number Diff line number Diff line change
Expand Up @@ -141,14 +141,21 @@ export interface PartialApplicationCommand {
description_localizations?: Record<string, string> | null;
/** The options for the command. */
options?: ApplicationCommandOption[];
/** Whether to enable this command for everyone by default. */
/**
* Whether to enable this command for everyone by default.
* @deprecated
*/
default_permission?: boolean;
/** Whether to enable this command in direct messages. */
dm_permission?: boolean | null;
/** The member permissions required to use this command. */
default_member_permissions?: string | null;
/** Whether this command is age-restricted. */
nsfw?: boolean | null;
/** The interaction contexts where this command is available. */
integration_types?: ApplicationIntegrationType[];
/** The interaction contexts where this command can be used. */
contexts?: InteractionContextType[] | null;
/** The type of application this is representing. `1` by default. */
type?: ApplicationCommandType;
}
Expand Down Expand Up @@ -292,6 +299,24 @@ export enum ApplicationCommandPermissionType {
CHANNEL = 3
}

/** The type of context an interaction can apply to. */
export enum InteractionContextType {
/** Interaction can be used within servers */
GUILD = 0,
/** Interaction can be used within DMs with the app's bot user */
BOT_DM = 1,
/** Interaction can be used within Group DMs and DMs other than the app's bot user */
PRIVATE_CHANNEL = 2
}

/** The type of context an app can install to. */
export enum ApplicationIntegrationType {
/** App is installable to guilds. */
GUILD_INSTALL = 0,
/** App is installable to users. */
USER_INSTALL = 1
}

/** A permission in a command. */
export interface ApplicationCommandPermissions {
id: string;
Expand Down Expand Up @@ -370,6 +395,8 @@ export interface DMModalSubmitRequestData {
message?: MessageData;
app_permissions?: string;
entitlements: AppEntitlement[];
authorizing_integration_owners?: Record<ApplicationIntegrationType, string>;
context?: InteractionContextType;
data: {
custom_id: string;
components: ComponentActionRow[];
Expand All @@ -394,6 +421,8 @@ export interface GuildModalSubmitRequestData {
message?: MessageData;
app_permissions?: string;
entitlements: AppEntitlement[];
authorizing_integration_owners?: Record<ApplicationIntegrationType, string>;
context?: InteractionContextType;
data: {
custom_id: string;
components: ComponentActionRow[];
Expand Down Expand Up @@ -422,6 +451,8 @@ export interface DMInteractionRequestData {
channel: CommandChannel;
app_permissions?: string;
entitlements: AppEntitlement[];
authorizing_integration_owners?: Record<ApplicationIntegrationType, string>;
context?: InteractionContextType;
data: CommandData;
}

Expand All @@ -443,6 +474,8 @@ export interface GuildInteractionRequestData {
channel: CommandChannel;
app_permissions?: string;
entitlements: AppEntitlement[];
authorizing_integration_owners?: Record<ApplicationIntegrationType, string>;
context?: InteractionContextType;
data: CommandData;
}

Expand Down
11 changes: 10 additions & 1 deletion src/structures/interfaces/baseInteraction.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@ import { BaseSlashCreator } from '../../creator';
import { Member } from '../member';
import { User } from '../user';
import { Permissions } from '../permissions';
import { AppEntitlement, AttachmentData } from '../../constants';
import { AppEntitlement, ApplicationIntegrationType, AttachmentData, InteractionContextType } from '../../constants';
import { Collection } from '../../util/collection';
import { Channel } from '../channel';
import { Message } from '../message';
Expand Down Expand Up @@ -37,6 +37,13 @@ export class BaseInteractionContext {
readonly appPermissions?: Permissions;
/** The entitlements the invoking user has. */
readonly entitlements: AppEntitlement[];
/**
* The map of owner IDs that this interaction was authorized for.
* @see https://discord.com/developers/docs/interactions/receiving-and-responding#interaction-object-authorizing-integration-owners-object
*/
readonly authorizingIntegrationOwners?: Record<ApplicationIntegrationType, string>;
/** The context that this interaction comes from. */
readonly context?: InteractionContextType;

/** The resolved users of the interaction. */
readonly users = new Collection<string, User>();
Expand Down Expand Up @@ -69,6 +76,8 @@ export class BaseInteractionContext {
this.channel = new Channel(data.channel);
this.appPermissions = data.app_permissions ? new Permissions(BigInt(data.app_permissions)) : undefined;
this.entitlements = data.entitlements;
if (data.authorizing_integration_owners) this.authorizingIntegrationOwners = data.authorizing_integration_owners;
if ('context' in data) this.context = data.context;

if (data.data.resolved) {
if (data.data.resolved.users)
Expand Down
62 changes: 59 additions & 3 deletions src/structures/message.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
import { AnyComponent, InteractionType, UserObject } from '../constants';
import { AnyComponent, ApplicationIntegrationType, InteractionType, UserObject } from '../constants';
import { EditMessageOptions } from './interfaces/messageInteraction';
import { BaseSlashCreator } from '../creator';
import { MessageInteractionContext } from './interfaces/messageInteraction';
Expand Down Expand Up @@ -42,8 +42,13 @@ export class Message {
readonly messageReference?: MessageReference;
/** The message's webhook ID */
readonly webhookID: string;
/** The interaction this message is apart of */
/**
* The interaction this message is apart of
* @deprecated Discord-imposed deprecation in favor of {@see Message#interactionMetadata}
*/
readonly interaction?: MessageInteraction;
/** The metadata of the interaction this message is apart of */
readonly interactionMetadata?: MessageInteractionMetadata;

/** The context that created the message class */
private readonly _ctx?: MessageInteractionContext;
Expand All @@ -55,6 +60,7 @@ export class Message {
constructor(data: MessageData, creator: BaseSlashCreator, ctx?: MessageInteractionContext) {
if (ctx) this._ctx = ctx;

console.log(data);
this.id = data.id;
this.type = data.type;
this.content = data.content;
Expand Down Expand Up @@ -85,6 +91,21 @@ export class Message {
name: data.interaction.name,
user: new User(data.interaction.user, creator)
};
if (data.interaction_metadata)
this.interactionMetadata = this.#convertInteractionMetadata(data.interaction_metadata);
}

#convertInteractionMetadata(metadata: MessageData['interaction_metadata']): MessageInteractionMetadata | undefined {
if (!metadata) return undefined;
return {
id: metadata.id,
type: metadata.type,
userID: metadata.user_id,
authorizingIntegrationOwners: metadata.authorizing_integration_owners,
originalResponseMessageID: metadata.original_response_message_id,
interactedMessageID: metadata.interacted_message_id,
triggeringInteractionMetadata: this.#convertInteractionMetadata(metadata.triggering_interaction_metadata)
};
}

/**
Expand All @@ -108,7 +129,8 @@ export class Message {
}
}

/** A message interaction. */
/**
* A message interaction. */
export interface MessageInteraction {
/** The ID of the interaction. */
id: string;
Expand All @@ -120,6 +142,24 @@ export interface MessageInteraction {
user: User;
}

/** Th emetadata of a message interaction. */
export interface MessageInteractionMetadata {
/** The ID of the interaction. */
id: string;
/** The type of interaction. */
type: InteractionType;
/** The ID of the user who invoked the interaction. */
userID: string;
/** The IDs of the installation contexts that are related to the interaction. */
authorizingIntegrationOwners: Record<ApplicationIntegrationType, string>;
/** ID of the original response message, only on follow-up messages. */
originalResponseMessageID?: string;
/** ID of the message that contained the interactive component that created this interaction. */
interactedMessageID?: string;
/** Metadata for the interaction that was used to open the modal, for modal submit interactions. */
triggeringInteractionMetadata?: MessageInteractionMetadata;
}

/** A message reference. */
export interface MessageReference {
/** The ID of the channel the reference is from. */
Expand Down Expand Up @@ -252,6 +292,22 @@ export interface MessageData {
name: string;
user: UserObject;
};
interaction_metadata?: {
id: string;
type: InteractionType;
user_id: string;
authorizing_integration_owners: Record<ApplicationIntegrationType, string>;
original_response_message_id?: string;
interacted_message_id?: string;
triggering_interaction_metadata?: {
id: string;
type: InteractionType;
user_id: string;
authorizing_integration_owners: Record<ApplicationIntegrationType, string>;
original_response_message_id?: string;
interacted_message_id?: string;
};
};
webhook_id: string;
message_reference?: {
channel_id: string;
Expand Down

0 comments on commit 9210885

Please sign in to comment.