Skip to content

Commit

Permalink
User installed apps
Browse files Browse the repository at this point in the history
  • Loading branch information
DonovanDMC committed Mar 19, 2024
1 parent 9b42887 commit a36e623
Show file tree
Hide file tree
Showing 15 changed files with 336 additions and 109 deletions.
11 changes: 11 additions & 0 deletions lib/Constants.ts
Original file line number Diff line number Diff line change
Expand Up @@ -112,6 +112,17 @@ export enum UserFlags {
RESTRICTED_COLLABORATOR = 2 ** 51,
}

export enum ApplicationIntegrationTypes {
GUILD_INSTALL = 0,
USER_INSTALL = 1,
}

export enum InteractionContextTypes {
GUILD = 0,
BOT_DM = 1,
PRIVATE_CHANNEL = 2,
}

export enum ApplicationFlags {
EMBEDDED_RELEASED = 1 << 1,
MANAGED_EMOJI = 1 << 2,
Expand Down
9 changes: 8 additions & 1 deletion lib/routes/Applications.ts
Original file line number Diff line number Diff line change
Expand Up @@ -49,10 +49,12 @@ export default class Applications {
method: "PUT",
path: Routes.APPLICATION_COMMANDS(applicationID),
json: opts.map(opt => ({
default_member_permissions: opt.defaultMemberPermissions,
contexts: opt.contexts,
description: opt.description,
default_member_permissions: opt.defaultMemberPermissions,
description_localizations: opt.descriptionLocalizations,
dm_permission: opt.dmPermission,
integration_types: opt.integrationTypes,
name: opt.name,
name_localizations: opt.nameLocalizations,
nsfw: opt.nsfw,
Expand Down Expand Up @@ -101,10 +103,12 @@ export default class Applications {
method: "POST",
path: Routes.APPLICATION_COMMANDS(applicationID),
json: {
contexts: opt.contexts,
default_member_permissions: opt.defaultMemberPermissions,
description: opt.description,
description_localizations: opt.descriptionLocalizations,
dm_permission: opt.dmPermission,
integration_types: opt.integrationTypes,
name: opt.name,
name_localizations: opt.nameLocalizations,
nsfw: opt.nsfw,
Expand Down Expand Up @@ -220,6 +224,7 @@ export default class Applications {
flags: options.flags,
icon: options.icon,
install_params: options.installParams,
integration_types_config: options.integrationTypesConfig,
interactions_endpoint_url: options.interactionsEndpointURL,
role_connections_verification_url: options.roleConnectionsVerificationURL,
tags: options.tags
Expand All @@ -240,10 +245,12 @@ export default class Applications {
method: "PATCH",
path: Routes.APPLICATION_COMMAND(applicationID, commandID),
json: {
contexts: opt.contexts,
default_member_permissions: opt.defaultMemberPermissions,
description: opt.description,
description_localizations: opt.descriptionLocalizations,
dm_permission: opt.dmPermission,
integration_types: opt.integrationTypes,
name: opt.name,
name_localizations: opt.nameLocalizations,
nsfw: opt.nsfw,
Expand Down
18 changes: 16 additions & 2 deletions lib/structures/Application.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3,10 +3,10 @@ import ClientApplication from "./ClientApplication";
import OAuthGuild from "./OAuthGuild";
import type Client from "../Client";
import type { InstallParams } from "../types/oauth";
import type { ImageFormat } from "../Constants";
import type { ApplicationIntegrationTypes, ImageFormat } from "../Constants";
import * as Routes from "../util/Routes";
import type { JSONApplication } from "../types/json";
import type { RESTApplication } from "../types";
import type { IntegrationTypesConfig, RESTApplication } from "../types";

/** Represents an application. */
export default class Application extends ClientApplication {
Expand All @@ -26,6 +26,10 @@ export default class Application extends ClientApplication {
icon: string | null;
/** Settings for this application's in-app authorization link, if enabled. */
installParams?: InstallParams;
/** The install types available for this application. */
integrationTypes: Array<ApplicationIntegrationTypes>;
/** The configs for the install types available for this application. */
integrationTypesConfig: IntegrationTypesConfig;
/** This applications interaction endpoint url, if any. */
interactionsEndpointURL: string | null;
/** The name of the application. */
Expand Down Expand Up @@ -56,6 +60,8 @@ export default class Application extends ClientApplication {
this.guild = null;
this.guildID = data.guild_id ?? null;
this.icon = null;
this.integrationTypes = [];
this.integrationTypesConfig = {};
this.interactionsEndpointURL = null;
this.name = data.name;
this.roleConnectionsVerificationURL = null;
Expand Down Expand Up @@ -89,6 +95,12 @@ export default class Application extends ClientApplication {
if (data.install_params !== undefined) {
this.installParams = data.install_params;
}
if (data.integration_types !== undefined) {
this.integrationTypes = data.integration_types;
}
if (data.integration_types_config !== undefined) {
this.integrationTypesConfig = Object.fromEntries(Object.entries(data.integration_types_config).map(([key, value]) => [key, { oauth2InstallParams: value.oauth2_install_params }]));
}
if (data.interactions_endpoint_url !== undefined) {
this.interactionsEndpointURL = data.interactions_endpoint_url;
}
Expand Down Expand Up @@ -153,6 +165,8 @@ export default class Application extends ClientApplication {
guildID: this.guildID,
icon: this.icon,
installParams: this.installParams,
integrationTypes: this.integrationTypes,
integrationTypesConfig: this.integrationTypesConfig,
interactionsEndpointURL: this.interactionsEndpointURL,
name: this.name,
primarySKUID: this.primarySKUID,
Expand Down
10 changes: 9 additions & 1 deletion lib/structures/ApplicationCommand.ts
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@ import Permission from "./Permission";
import type Guild from "./Guild";
import type ClientApplication from "./ClientApplication";
import type Client from "../Client";
import { ApplicationCommandTypes } from "../Constants";
import { ApplicationCommandTypes, type InteractionContextTypes, type ApplicationIntegrationTypes } from "../Constants";
import type {
ApplicationCommandOptionConversion,
ApplicationCommandOptions,
Expand All @@ -24,6 +24,8 @@ export default class ApplicationCommand<T extends ApplicationCommandTypes = Appl
application?: ClientApplication;
/** The ID of application this command is for. */
applicationID: string;
/** The contexts in which this application command can be used in. */
contexts: Array<InteractionContextTypes>;
/** The default permissions for this command. */
defaultMemberPermissions: Permission | null;
/** The description of this command. Empty string for non `CHAT_INPUT` commands. */
Expand All @@ -36,6 +38,8 @@ export default class ApplicationCommand<T extends ApplicationCommandTypes = Appl
dmPermission?: boolean;
/** The id of the guild this command is in (guild commands only). */
guildID: string | null;
/** The installation contexts in which this command is available. */
integrationTypes: Array<ApplicationIntegrationTypes>;
/** The name of this command. */
name: string;
/** A dictionary of [locales](https://discord.com/developers/docs/reference#locales) to localized names. */
Expand All @@ -54,12 +58,14 @@ export default class ApplicationCommand<T extends ApplicationCommandTypes = Appl
super(data.id, client);
this.application = client["_application"] && client.application.id === data.application_id ? client.application : undefined;
this.applicationID = data.application_id;
this.contexts = data.contexts;
this.defaultMemberPermissions = data.default_member_permissions ? new Permission(data.default_member_permissions) : null;
this.description = data.description as never;
this.descriptionLocalizations = data.description_localizations;
this.descriptionLocalized = data.description_localized;
this.dmPermission = data.dm_permission;
this.guildID = data.guild_id ?? null;
this.integrationTypes = data.integration_types;
this.name = data.name;
this.nameLocalizations = data.name_localizations;
this.nameLocalized = data.name_localized;
Expand Down Expand Up @@ -135,11 +141,13 @@ export default class ApplicationCommand<T extends ApplicationCommandTypes = Appl
return {
...super.toJSON(),
applicationID: this.applicationID,
contexts: this.contexts,
defaultMemberPermissions: this.defaultMemberPermissions?.toJSON(),
description: this.description,
descriptionLocalizations: this.descriptionLocalizations,
dmPermission: this.dmPermission,
guildID: this.guildID ?? undefined,
integrationTypes: this.integrationTypes,
name: this.name,
nameLocalizations: this.nameLocalizations,
nsfw: this.nsfw,
Expand Down
43 changes: 29 additions & 14 deletions lib/structures/AutocompleteInteraction.ts
Original file line number Diff line number Diff line change
Expand Up @@ -8,8 +8,14 @@ import GuildChannel from "./GuildChannel";
import type PrivateChannel from "./PrivateChannel";
import type Entitlement from "./Entitlement";
import type TestEntitlement from "./TestEntitlement";
import { InteractionResponseTypes, type InteractionTypes } from "../Constants";
import type { AutocompleteChoice, AutocompleteInteractionData, InteractionGuild, RawAutocompleteInteraction } from "../types/interactions";
import { InteractionResponseTypes, type InteractionTypes, type InteractionContextTypes } from "../Constants";
import type {
AuthorizingIntegrationOwners,
AutocompleteChoice,
AutocompleteInteractionData,
InteractionGuild,
RawAutocompleteInteraction
} from "../types/interactions";
import type Client from "../Client";
import type { AnyTextableGuildChannel, AnyInteractionChannel } from "../types/channels";
import type { JSONAutocompleteInteraction } from "../types/json";
Expand All @@ -21,10 +27,14 @@ import { UncachedError } from "../util/Errors";
export default class AutocompleteInteraction<T extends AnyInteractionChannel | Uncached = AnyInteractionChannel | Uncached> extends Interaction {
private _cachedChannel!: T extends AnyInteractionChannel ? T : undefined;
private _cachedGuild?: T extends AnyTextableGuildChannel ? Guild : Guild | null;
/** The permissions the bot has in the channel this interaction was sent from, if this interaction is sent from a guild. */
appPermissions: T extends AnyTextableGuildChannel ? Permission : Permission | undefined;
/** The permissions the bot has in the channel this interaction was sent from. If in a dm/group dm, this will contain `ATTACH_FILES`, `EMBED_LINKS`, and `MENTION_EVERYONE`. In addition, `USE_EXTERNAL_EMOJIS` will be included for DMs with the app's bot user. */
appPermissions: Permission;
/** Details about the authorizing user or server for the installation(s) relevant to the interaction. See [Discord's docs](https://discord.com/developers/docs/interactions/receiving-and-responding#interaction-object-authorizing-integration-owners-object) for more information. */
authorizingIntegrationOwners: AuthorizingIntegrationOwners;
/** The ID of the channel this interaction was sent from. */
channelID: string;
/** The context this interaction was sent from. */
context?: InteractionContextTypes;
/** The data associated with the interaction. */
data: AutocompleteInteractionData;
/** The entitlements for the user that created this interaction, and the guild it was created in. */
Expand All @@ -46,8 +56,10 @@ export default class AutocompleteInteraction<T extends AnyInteractionChannel | U
user: User;
constructor(data: RawAutocompleteInteraction, client: Client) {
super(data, client);
this.appPermissions = (data.app_permissions === undefined ? undefined : new Permission(data.app_permissions)) as T extends AnyTextableGuildChannel ? Permission : Permission | undefined;
this.appPermissions = new Permission(data.app_permissions ?? "0");
this.authorizingIntegrationOwners = data.authorizing_integration_owners;
this.channelID = data.channel_id!;
this.context = data.context;
this.data = {
guildID: data.data.guild_id,
id: data.data.id,
Expand Down Expand Up @@ -109,15 +121,18 @@ export default class AutocompleteInteraction<T extends AnyInteractionChannel | U
override toJSON(): JSONAutocompleteInteraction {
return {
...super.toJSON(),
appPermissions: this.appPermissions?.toJSON(),
channel: this.channelID,
data: this.data,
guildID: this.guildID ?? undefined,
guildLocale: this.guildLocale,
locale: this.locale,
member: this.member?.toJSON(),
type: this.type,
user: this.user.toJSON()
appPermissions: this.appPermissions.toJSON(),
authorizingIntegrationOwners: this.authorizingIntegrationOwners,
channel: this.channelID, // TODO: remove in 1.10.0
channelID: this.channelID,
context: this.context,
data: this.data,
guildID: this.guildID ?? undefined,
guildLocale: this.guildLocale,
locale: this.locale,
member: this.member?.toJSON(),
type: this.type,
user: this.user.toJSON()
};
}
}
37 changes: 23 additions & 14 deletions lib/structures/CommandInteraction.ts
Original file line number Diff line number Diff line change
Expand Up @@ -13,15 +13,16 @@ import InteractionResolvedChannel from "./InteractionResolvedChannel";
import type Entitlement from "./Entitlement";
import type TestEntitlement from "./TestEntitlement";
import TypedCollection from "../util/TypedCollection";
import { ApplicationCommandTypes, InteractionResponseTypes, type InteractionTypes } from "../Constants";
import { ApplicationCommandTypes, InteractionResponseTypes, type InteractionTypes, type InteractionContextTypes } from "../Constants";
import type {
ApplicationCommandInteractionData,
InteractionContent,
ModalData,
RawApplicationCommandInteraction,
ApplicationCommandInteractionResolvedData,
InitialInteractionContent,
InteractionGuild
InteractionGuild,
AuthorizingIntegrationOwners
} from "../types/interactions";
import type Client from "../Client";
import type { RawMember } from "../types/guilds";
Expand All @@ -37,10 +38,14 @@ import MessageInteractionResponse, { type FollowupMessageInteractionResponse, ty
export default class CommandInteraction<T extends AnyInteractionChannel | Uncached = AnyInteractionChannel | Uncached, C extends ApplicationCommandTypes = ApplicationCommandTypes> extends Interaction {
private _cachedChannel!: T extends AnyInteractionChannel ? T : undefined;
private _cachedGuild?: T extends AnyTextableGuildChannel ? Guild : Guild | null;
/** The permissions the bot has in the channel this interaction was sent from, if this interaction is sent from a guild. */
appPermissions: T extends AnyTextableGuildChannel ? Permission : Permission | undefined;
/** The permissions the bot has in the channel this interaction was sent from. If in a dm/group dm, this will contain `ATTACH_FILES`, `EMBED_LINKS`, and `MENTION_EVERYONE`. In addition, `USE_EXTERNAL_EMOJIS` will be included for DMs with the app's bot user. */
appPermissions: Permission;
/** Details about the authorizing user or server for the installation(s) relevant to the interaction. See [Discord's docs](https://discord.com/developers/docs/interactions/receiving-and-responding#interaction-object-authorizing-integration-owners-object) for more information. */
authorizingIntegrationOwners: AuthorizingIntegrationOwners;
/** The ID of the channel this interaction was sent from. */
channelID: string;
/** The context this interaction was sent from. */
context?: InteractionContextTypes;
/** The data associated with the interaction. */
data: ApplicationCommandInteractionData<T, C>;
/** The entitlements for the user that created this interaction, and the guild it was created in. */
Expand All @@ -62,8 +67,10 @@ export default class CommandInteraction<T extends AnyInteractionChannel | Uncach
user: User;
constructor(data: RawApplicationCommandInteraction, client: Client) {
super(data, client);
this.appPermissions = (data.app_permissions === undefined ? undefined : new Permission(data.app_permissions)) as T extends AnyTextableGuildChannel ? Permission : Permission | undefined;
this.appPermissions = new Permission(data.app_permissions ?? "0");
this.authorizingIntegrationOwners = data.authorizing_integration_owners;
this.channelID = data.channel_id!;
this.context = data.context;
const resolved: ApplicationCommandInteractionResolvedData = {
attachments: new TypedCollection(Attachment, client),
channels: new TypedCollection(InteractionResolvedChannel, client),
Expand Down Expand Up @@ -316,15 +323,17 @@ export default class CommandInteraction<T extends AnyInteractionChannel | Uncach
override toJSON(): JSONCommandInteraction {
return {
...super.toJSON(),
appPermissions: this.appPermissions?.toJSON(),
channelID: this.channelID,
data: this.data,
guildID: this.guildID ?? undefined,
guildLocale: this.guildLocale,
locale: this.locale,
member: this.member?.toJSON(),
type: this.type,
user: this.user.toJSON()
appPermissions: this.appPermissions.toJSON(),
authorizingIntegrationOwners: this.authorizingIntegrationOwners,
channelID: this.channelID,
context: this.context,
data: this.data,
guildID: this.guildID ?? undefined,
guildLocale: this.guildLocale,
locale: this.locale,
member: this.member?.toJSON(),
type: this.type,
user: this.user.toJSON()
};
}
}
Loading

0 comments on commit a36e623

Please sign in to comment.