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: user-installable apps #10227

Merged
merged 54 commits into from
Sep 1, 2024
Merged
Show file tree
Hide file tree
Changes from 6 commits
Commits
Show all changes
54 commits
Select commit Hold shift + click to select a range
d5c6961
feat: inital user-installable apps support
Syjalo Apr 24, 2024
5088fad
docs: add deprecation warnings
Syjalo Apr 25, 2024
b580bd3
Merge branch 'main' into feat/user-installable-app
Syjalo May 13, 2024
f10a3fe
Merge branch 'main' into feat/user-installable-app
Jiralite May 13, 2024
548de0f
Merge branch 'main' into feat/user-installable-app
Syjalo Jun 6, 2024
b198465
feat: add equality checks
Syjalo Jun 19, 2024
1df40d0
fix: possibly `null` cases
Syjalo Jun 20, 2024
e8f97ac
docs: tweaks
Jiralite Jul 9, 2024
0a2dacb
Merge branch 'main' into feat/user-installable-app
Jiralite Jul 9, 2024
f6a823f
docs: add deprecations
Jiralite Jul 9, 2024
c50fe30
fix(ApplicationCommandManager): amend transform command
Jiralite Jul 9, 2024
92b7fea
feat: properly support `integration_types_config`
Jiralite Jul 9, 2024
876686c
docs: add .
Jiralite Jul 9, 2024
5c13949
docs: minor changes
Jiralite Jul 9, 2024
51f7078
featBaseApplicationCommandData): update type
Jiralite Jul 9, 2024
92c5546
style: prettier
Jiralite Jul 9, 2024
685412c
chore: fix issues
Jiralite Jul 9, 2024
8253458
Merge branch 'main' into feat/user-installable-app
Jiralite Jul 9, 2024
e1d9350
fix: correct casing
Jiralite Jul 21, 2024
2f20eeb
refactor: remove console log
Syjalo Aug 10, 2024
9ea527c
fix: use case that satisfies `/core` and the API
Syjalo Aug 10, 2024
c99752a
fix: `oauth2InstallParams` property is not nullable
Syjalo Aug 10, 2024
b68015d
fix: do not convert keys into strings
Syjalo Aug 10, 2024
a256136
feat: update transforer to return the full map
Syjalo Aug 10, 2024
50c0309
feat: update transformers
Syjalo Aug 10, 2024
50f03fa
feat: add `PartialGroupDMMessageManager `
Syjalo Aug 14, 2024
a62472f
docs: fix type
Syjalo Aug 15, 2024
4509116
feat: add approximate count of users property
Syjalo Aug 15, 2024
4670ca2
fix: messageCreate doesn't emit in PartialGroupDMChannel
Syjalo Aug 17, 2024
bfabc23
fix: add GroupDM to TextBasedChannelTypes
Syjalo Aug 17, 2024
2cc3bba
feat: add NonPartialGroupDMChannel helper
Syjalo Aug 18, 2024
12eab6a
fix: expect PartialGroupDMChannel
Syjalo Aug 18, 2024
b0e3f33
feat: narrow generic type
Syjalo Aug 18, 2024
d5465df
test: exclude PartialGroupDMChannel
Syjalo Aug 18, 2024
bfadec0
feat: use structure's channel type
Syjalo Aug 18, 2024
0043728
docs: narrow type
Syjalo Aug 20, 2024
5400e18
feat: remove transformer
Syjalo Aug 20, 2024
50319a5
refactor: remove unnecessary parse
Syjalo Aug 20, 2024
21c86d8
feat: add APIAutoModerationAction transformer
Syjalo Aug 20, 2024
22b46d7
Merge branch 'main' into feat/user-installable-app
Syjalo Aug 21, 2024
49c6fd5
fix: use the right transformer during recursive parsing of interactio…
vladfrangu Aug 21, 2024
86cd370
docs: add external types
Syjalo Aug 28, 2024
c5d87e3
docs: add `Message#interactionMetadata` property docs
Syjalo Aug 28, 2024
e6e8231
docs: make nullable
Syjalo Aug 28, 2024
708dad3
Merge branch 'main' into feat/user-installable-app
Syjalo Aug 28, 2024
e4006a5
docs: add d-docs link
Syjalo Aug 28, 2024
557be0d
docs: use optional
Syjalo Aug 28, 2024
19c3222
fix: make `oauth2InstallParams` nullable
Syjalo Aug 29, 2024
1f516a4
types: update `IntegrationTypesConfiguration`
Syjalo Aug 29, 2024
933aa20
docs: update `IntegrationTypesConfigurationParameters`
Syjalo Aug 29, 2024
72f9251
types: update `IntegrationTypesConfigurationParameters`
Syjalo Aug 29, 2024
2b25024
refactor: improve readability
Syjalo Aug 29, 2024
9d61a22
docs: mark integrationTypesConfig nullable
Syjalo Aug 31, 2024
b2e0d7d
refactor: requested changes
almeidx Sep 1, 2024
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
27 changes: 26 additions & 1 deletion packages/discord.js/src/structures/ApplicationCommand.js
Original file line number Diff line number Diff line change
Expand Up @@ -145,12 +145,35 @@ class ApplicationCommand extends Base {
* Whether the command can be used in DMs
* <info>This property is always `null` on guild commands</info>
* @type {?boolean}
* @deprecated Use {@link ApplicationCommand#contexts} instead.
*/
this.dmPermission = data.dm_permission;
} else {
this.dmPermission ??= null;
}

if ('integration_types' in data) {
/**
* Installation context(s) where the command is available
* <info>Only for globally-scoped commands</info>
* @type {?ApplicationIntegrationType[]}
Syjalo marked this conversation as resolved.
Show resolved Hide resolved
*/
this.integrationTypes = data.integration_types;
} else {
this.integrationTypes ??= null;
}

if ('contexts' in data) {
/**
* Interaction context(s) where the command can be used
* <info>Only for globally-scoped commands</info>
* @type {?InteractionContextType[]}
Syjalo marked this conversation as resolved.
Show resolved Hide resolved
*/
this.contexts = data.contexts;
} else {
this.contexts ??= null;
}

if ('version' in data) {
/**
* Autoincrementing version identifier updated during substantial record changes
Expand Down Expand Up @@ -394,7 +417,9 @@ class ApplicationCommand extends Base {
!isEqual(
command.descriptionLocalizations ?? command.description_localizations ?? {},
this.descriptionLocalizations ?? {},
)
) ||
!isEqual(command.integrationTypes ?? command.integration_types ?? [], this.integrationTypes) ||
!isEqual(command.contexts ?? [], this.contexts)
Syjalo marked this conversation as resolved.
Show resolved Hide resolved
) {
return false;
}
Expand Down
4 changes: 2 additions & 2 deletions packages/discord.js/src/structures/BaseInteraction.js
Original file line number Diff line number Diff line change
Expand Up @@ -75,9 +75,9 @@ class BaseInteraction extends Base {

/**
* Set of permissions the application or bot has within the channel the interaction was sent from
* @type {?Readonly<PermissionsBitField>}
* @type {Readonly<PermissionsBitField>}
*/
this.appPermissions = data.app_permissions ? new PermissionsBitField(data.app_permissions).freeze() : null;
this.appPermissions = new PermissionsBitField(data.app_permissions).freeze();

/**
* The permissions of the member, if one exists, in the channel this interaction was executed in
Expand Down
10 changes: 10 additions & 0 deletions packages/discord.js/src/structures/ClientApplication.js
Original file line number Diff line number Diff line change
Expand Up @@ -61,6 +61,16 @@ class ClientApplication extends Application {
this.installParams ??= null;
}

if ('integration_types_config' in data) {
/**
* Default scopes and permissions for each supported installation context
* @type {APIApplicationIntegrationTypesConfigMap}
*/
this.integrationTypesConfig = data.integration_types_config;
} else {
this.integrationTypesConfig ??= null;
}

if ('custom_install_url' in data) {
/**
* This application's custom installation URL
Expand Down
12 changes: 12 additions & 0 deletions packages/discord.js/src/structures/CommandInteraction.js
Original file line number Diff line number Diff line change
Expand Up @@ -45,6 +45,18 @@ class CommandInteraction extends BaseInteraction {
*/
this.commandGuildId = data.data.guild_id ?? null;

/**
* Mapping of installation contexts that the interaction was authorized for to related user or guild IDs
* @type {APIAuthorizingIntegrationOwnersMap}
Syjalo marked this conversation as resolved.
Show resolved Hide resolved
*/
Jiralite marked this conversation as resolved.
Show resolved Hide resolved
this.authorizingIntegrationOwners = data.authorizingIntegrationOwners;

/**
* Context where the interaction was triggered from
* @type {?InteractionContextType}
*/
this.context = data.context ?? null;

/**
* Whether the reply to this interaction has been deferred
* @type {boolean}
Expand Down
31 changes: 31 additions & 0 deletions packages/discord.js/src/structures/Message.js
Original file line number Diff line number Diff line change
Expand Up @@ -383,6 +383,36 @@ class Message extends Base {
this.channel?.messages._add({ guild_id: data.message_reference?.guild_id, ...data.referenced_message });
}

if (data.interaction_metadata) {
/**
* Partial data of the interaction that this message is a result of
* @typedef {Object} MessageInteractionMetadata
* @property {Snowflake} id The interaction's id
* @property {InteractionType} type The type of the interaction
* @property {User} user The user that invoked the interaction
* @property {APIAuthorizingIntegrationOwnersMap} authorizingIntegrationOwners
* IDs for installation context(s) related to an interaction
* @property {?Snowflake} originalResponseMessageId
* ID of the original response message, present only on follow-up messages
* @property {?Snowflake} interactedMessageId
* ID of the message that contained interactive component,
* present only on messages created from component interactions
* @property {?MessageInteractionMetadata} triggeringInteractionMetadata
* Metadata for the interaction that was used to open the modal, present only on modal submit interactions
*/
Jiralite marked this conversation as resolved.
Show resolved Hide resolved
this.interactionMetadata = {
id: data.interaction_metadata.id,
type: data.interaction_metadata.type,
user: this.client.users._add(data.interaction_metadata.user),
authorizingIntegrationOwners: data.interaction_metadata.authorizing_integration_owners,
originalResponseMessageId: data.interaction_metadata.original_response_message_id ?? null,
interactedMessageId: data.interaction_metadata.interacted_message_id ?? null,
triggeringInteractionMetadata: data.interaction_metadata.triggering_interaction_metadata ?? null,
Syjalo marked this conversation as resolved.
Show resolved Hide resolved
};
} else {
this.interactionMetadata ??= null;
}

/**
* Partial data of the interaction that a message is a reply to
* @typedef {Object} MessageInteraction
Expand All @@ -391,6 +421,7 @@ class Message extends Base {
* @property {string} commandName The name of the interaction's application command,
* as well as the subcommand and subcommand group, where applicable
* @property {User} user The user that invoked the interaction
* @deprecated Use {@link Message#interactionMetadata} instead.
*/

if (data.interaction) {
Expand Down
22 changes: 21 additions & 1 deletion packages/discord.js/typings/index.d.ts
Original file line number Diff line number Diff line change
Expand Up @@ -175,6 +175,9 @@ import {
SKUType,
APIEntitlement,
EntitlementType,
ApplicationIntegrationType,
InteractionContextType,
APIAuthorizingIntegrationOwnersMap,
APIPoll,
PollLayoutType,
APIPollAnswer,
Expand Down Expand Up @@ -441,17 +444,20 @@ export abstract class Application extends Base {
export class ApplicationCommand<PermissionsFetchType = {}> extends Base {
private constructor(client: Client<true>, data: RawApplicationCommandData, guild?: Guild, guildId?: Snowflake);
public applicationId: Snowflake;
public contexts: InteractionContextType[] | null;
public get createdAt(): Date;
public get createdTimestamp(): number;
public defaultMemberPermissions: Readonly<PermissionsBitField> | null;
public description: string;
public descriptionLocalizations: LocalizationMap | null;
public descriptionLocalized: string | null;
/** @deprecated Use {@link ApplicationCommand.contexts} instead */
public dmPermission: boolean | null;
public guild: Guild | null;
public guildId: Snowflake | null;
public get manager(): ApplicationCommandManager;
public id: Snowflake;
public integrationTypes: ApplicationIntegrationType[] | null;
Jiralite marked this conversation as resolved.
Show resolved Hide resolved
public name: string;
public nameLocalizations: LocalizationMap | null;
public nameLocalized: string | null;
Expand Down Expand Up @@ -553,6 +559,7 @@ export type GuildCacheMessage<Cached extends CacheType> = CacheTypeReducer<
export type BooleanCache<Cached extends CacheType> = Cached extends 'cached' ? true : false;

export abstract class CommandInteraction<Cached extends CacheType = CacheType> extends BaseInteraction<Cached> {
public authorizingIntegrationOwners: APIAuthorizingIntegrationOwnersMap;
public type: InteractionType.ApplicationCommand;
public get command(): ApplicationCommand | ApplicationCommand<{ guild: GuildResolvable }> | null;
public options: Omit<
Expand All @@ -577,6 +584,7 @@ export abstract class CommandInteraction<Cached extends CacheType = CacheType> e
public commandName: string;
public commandType: ApplicationCommandType;
public commandGuildId: Snowflake | null;
public context: InteractionContextType | null;
public deferred: boolean;
public ephemeral: boolean | null;
public replied: boolean;
Expand Down Expand Up @@ -1890,7 +1898,7 @@ export class BaseInteraction<Cached extends CacheType = CacheType> extends Base
public type: InteractionType;
public user: User;
public version: number;
public appPermissions: CacheTypeReducer<Cached, Readonly<PermissionsBitField>>;
public appPermissions: Readonly<PermissionsBitField>;
public memberPermissions: CacheTypeReducer<Cached, Readonly<PermissionsBitField>>;
public locale: Locale;
public guildLocale: CacheTypeReducer<Cached, Locale>;
Expand Down Expand Up @@ -2102,7 +2110,9 @@ export class Message<InGuild extends boolean = boolean> extends Base {
public get guild(): If<InGuild, Guild>;
public get hasThread(): boolean;
public id: Snowflake;
/** @deprecated Use {@link Message.interactionMetadata} instead */
public interaction: MessageInteraction | null;
public interactionMetadata: MessageInteractionMetadata | null;
public get member(): GuildMember | null;
public mentions: MessageMentions<InGuild>;
public nonce: string | number | null;
Expand Down Expand Up @@ -6286,6 +6296,16 @@ export interface MessageComponentCollectorOptions<Interaction extends CollectedM
export interface MessageChannelComponentCollectorOptions<Interaction extends CollectedMessageInteraction>
extends Omit<InteractionCollectorOptions<Interaction>, 'channel' | 'guild' | 'interactionType'> {}

export interface MessageInteractionMetadata {
id: Snowflake;
type: InteractionType;
user: User;
authorizingIntegrationOwners: APIAuthorizingIntegrationOwnersMap;
originalResponseMessageId: Snowflake | null;
interactedMessageId: Snowflake | null;
triggeringInteractionMetadata: MessageInteractionMetadata | null;
}

export interface MessageInteraction {
id: Snowflake;
type: InteractionType;
Expand Down
Loading