feat: user-installable apps (#10227)

* feat: inital user-installable apps support

* docs: add deprecation warnings

* feat: add equality checks

* fix: possibly `null` cases

* docs: tweaks

* docs: add deprecations

* fix(ApplicationCommandManager): amend transform command

* feat: properly support `integration_types_config`

* docs: add .

* docs: minor changes

* featBaseApplicationCommandData): update type

* style: prettier

* chore: fix issues

* fix: correct casing

Co-authored-by: Superchupu <53496941+SuperchupuDev@users.noreply.github.com>

* refactor: remove console log

* fix: use case that satisfies `/core` and the API

* fix: `oauth2InstallParams` property is not nullable

* fix: do not convert keys into strings

* feat: update transforer to return the full map

* feat: update transformers

* feat: add `PartialGroupDMMessageManager `

Hope this is not a breaking change

* docs: fix type

* feat: add approximate count of users property

* fix: messageCreate doesn't emit in PartialGroupDMChannel

* fix: add GroupDM to TextBasedChannelTypes

* feat: add NonPartialGroupDMChannel helper

* fix: expect PartialGroupDMChannel

* feat: narrow generic type

* test: exclude PartialGroupDMChannel

* feat: use structure's channel type

* docs: narrow type

* feat: remove transformer

* refactor: remove unnecessary parse

* feat: add APIAutoModerationAction transformer

* fix: use the right transformer during recursive parsing of interaction metadata

* docs: add external types

* docs: add `Message#interactionMetadata` property docs

* docs: make nullable

* docs: add d-docs link

* docs: use optional

* fix: make `oauth2InstallParams` nullable

* types: update `IntegrationTypesConfiguration`

Co-authored-by: Almeida <github@almeidx.dev>

* docs: update `IntegrationTypesConfigurationParameters`

Co-authored-by: Almeida <github@almeidx.dev>

* types: update `IntegrationTypesConfigurationParameters`

* refactor: improve readability

* docs: mark integrationTypesConfig nullable

* refactor: requested changes

---------

Co-authored-by: Jiralite <33201955+Jiralite@users.noreply.github.com>
Co-authored-by: Superchupu <53496941+SuperchupuDev@users.noreply.github.com>
Co-authored-by: Vlad Frangu <me@vladfrangu.dev>
Co-authored-by: Almeida <github@almeidx.dev>
This commit is contained in:
Synbulat Biishev
2024-09-02 01:44:51 +05:00
committed by GitHub
parent a5afc406b9
commit fc0b6f7f8e
15 changed files with 278 additions and 27 deletions

View File

@@ -67,6 +67,8 @@ export class ContextMenuCommandBuilder {
* *
* @remarks * @remarks
* By default, commands are visible. This property is only for global commands. * By default, commands are visible. This property is only for global commands.
* @deprecated
* Use {@link ContextMenuCommandBuilder.contexts} instead.
*/ */
public readonly dm_permission: boolean | undefined = undefined; public readonly dm_permission: boolean | undefined = undefined;
@@ -167,6 +169,7 @@ export class ContextMenuCommandBuilder {
* By default, commands are visible. This method is only for global commands. * By default, commands are visible. This method is only for global commands.
* @param enabled - Whether the command should be enabled in direct messages * @param enabled - Whether the command should be enabled in direct messages
* @see {@link https://discord.com/developers/docs/interactions/application-commands#permissions} * @see {@link https://discord.com/developers/docs/interactions/application-commands#permissions}
* @deprecated Use {@link ContextMenuCommandBuilder.setContexts} instead.
*/ */
public setDMPermission(enabled: boolean | null | undefined) { public setDMPermission(enabled: boolean | null | undefined) {
// Assert the value matches the conditions // Assert the value matches the conditions

View File

@@ -63,6 +63,8 @@ export class SlashCommandBuilder {
* *
* @remarks * @remarks
* By default, commands are visible. This property is only for global commands. * By default, commands are visible. This property is only for global commands.
* @deprecated
* Use {@link SlashCommandBuilder.contexts} instead.
*/ */
public readonly dm_permission: boolean | undefined = undefined; public readonly dm_permission: boolean | undefined = undefined;

View File

@@ -43,6 +43,9 @@ export class SharedSlashCommand {
public readonly default_member_permissions: Permissions | null | undefined = undefined; public readonly default_member_permissions: Permissions | null | undefined = undefined;
/**
* @deprecated Use {@link SharedSlashCommand.contexts} instead.
*/
public readonly dm_permission: boolean | undefined = undefined; public readonly dm_permission: boolean | undefined = undefined;
public readonly integration_types?: ApplicationIntegrationType[]; public readonly integration_types?: ApplicationIntegrationType[];
@@ -113,6 +116,8 @@ export class SharedSlashCommand {
* By default, commands are visible. This method is only for global commands. * By default, commands are visible. This method is only for global commands.
* @param enabled - Whether the command should be enabled in direct messages * @param enabled - Whether the command should be enabled in direct messages
* @see {@link https://discord.com/developers/docs/interactions/application-commands#permissions} * @see {@link https://discord.com/developers/docs/interactions/application-commands#permissions}
* @deprecated
* Use {@link SharedSlashCommand.setContexts} instead.
*/ */
public setDMPermission(enabled: boolean | null | undefined) { public setDMPermission(enabled: boolean | null | undefined) {
// Assert the value matches the conditions // Assert the value matches the conditions

View File

@@ -259,6 +259,8 @@ class ApplicationCommandManager extends CachedManager {
options: command.options?.map(option => ApplicationCommand.transformOption(option)), options: command.options?.map(option => ApplicationCommand.transformOption(option)),
default_member_permissions, default_member_permissions,
dm_permission: command.dmPermission ?? command.dm_permission, dm_permission: command.dmPermission ?? command.dm_permission,
integration_types: command.integrationTypes ?? command.integration_types,
contexts: command.contexts,
}; };
} }
} }

View File

@@ -0,0 +1,17 @@
'use strict';
const MessageManager = require('./MessageManager');
/**
* Manages API methods for messages in group direct message channels and holds their cache.
* @extends {MessageManager}
*/
class PartialGroupDMMessageManager extends MessageManager {
/**
* The channel that the messages belong to
* @name PartialGroupDMMessageManager#channel
* @type {PartialGroupDMChannel}
*/
}
module.exports = PartialGroupDMMessageManager;

View File

@@ -145,12 +145,35 @@ class ApplicationCommand extends Base {
* Whether the command can be used in DMs * Whether the command can be used in DMs
* <info>This property is always `null` on guild commands</info> * <info>This property is always `null` on guild commands</info>
* @type {?boolean} * @type {?boolean}
* @deprecated Use {@link ApplicationCommand#contexts} instead.
*/ */
this.dmPermission = data.dm_permission; this.dmPermission = data.dm_permission;
} else { } else {
this.dmPermission ??= null; 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[]}
*/
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[]}
*/
this.contexts = data.contexts;
} else {
this.contexts ??= null;
}
if ('version' in data) { if ('version' in data) {
/** /**
* Autoincrementing version identifier updated during substantial record changes * Autoincrementing version identifier updated during substantial record changes
@@ -394,7 +417,9 @@ class ApplicationCommand extends Base {
!isEqual( !isEqual(
command.descriptionLocalizations ?? command.description_localizations ?? {}, command.descriptionLocalizations ?? command.description_localizations ?? {},
this.descriptionLocalizations ?? {}, this.descriptionLocalizations ?? {},
) ) ||
!isEqual(command.integrationTypes ?? command.integration_types ?? [], this.integrationTypes ?? {}) ||
!isEqual(command.contexts ?? [], this.contexts ?? [])
) { ) {
return false; return false;
} }

View File

@@ -75,9 +75,9 @@ class BaseInteraction extends Base {
/** /**
* Set of permissions the application or bot has within the channel the interaction was sent from * 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 * The permissions of the member, if one exists, in the channel this interaction was executed in

View File

@@ -15,8 +15,8 @@ const PermissionsBitField = require('../util/PermissionsBitField');
/** /**
* @typedef {Object} ClientApplicationInstallParams * @typedef {Object} ClientApplicationInstallParams
* @property {OAuth2Scopes[]} scopes The scopes to add the application to the server with * @property {OAuth2Scopes[]} scopes Scopes that will be set upon adding this application
* @property {Readonly<PermissionsBitField>} permissions The permissions this bot will request upon joining * @property {Readonly<PermissionsBitField>} permissions Permissions that will be requested for the integrated role
*/ */
/** /**
@@ -68,6 +68,56 @@ class ClientApplication extends Application {
this.installParams ??= null; this.installParams ??= null;
} }
/**
* OAuth2 installation parameters.
* @typedef {Object} IntegrationTypesConfigurationParameters
* @property {OAuth2Scopes[]} scopes Scopes that will be set upon adding this application
* @property {Readonly<PermissionsBitField>} permissions Permissions that will be requested for the integrated role
*/
/**
* The application's supported installation context data.
* @typedef {Object} IntegrationTypesConfigurationContext
* @property {?IntegrationTypesConfigurationParameters} oauth2InstallParams
* Scopes and permissions regarding the installation context
*/
/**
* The application's supported installation context data.
* @typedef {Object} IntegrationTypesConfiguration
* @property {IntegrationTypesConfigurationContext} [0] Scopes and permissions
* regarding the guild-installation context
* @property {IntegrationTypesConfigurationContext} [1] Scopes and permissions
* regarding the user-installation context
*/
if ('integration_types_config' in data) {
/**
* Default scopes and permissions for each supported installation context.
* The keys are stringified variants of {@link ApplicationIntegrationType}.
* @type {?IntegrationTypesConfiguration}
*/
this.integrationTypesConfig = Object.fromEntries(
Object.entries(data.integration_types_config).map(([key, config]) => {
let oauth2InstallParams = null;
if (config.oauth2_install_params) {
oauth2InstallParams = {
scopes: config.oauth2_install_params.scopes,
permissions: new PermissionsBitField(config.oauth2_install_params.permissions).freeze(),
};
}
const context = {
oauth2InstallParams,
};
return [key, context];
}),
);
} else {
this.integrationTypesConfig ??= null;
}
if ('custom_install_url' in data) { if ('custom_install_url' in data) {
/** /**
* This application's custom installation URL * This application's custom installation URL
@@ -96,6 +146,16 @@ class ClientApplication extends Application {
this.approximateGuildCount ??= null; this.approximateGuildCount ??= null;
} }
if ('approximate_user_install_count' in data) {
/**
* An approximate amount of users that have installed this application.
* @type {?number}
*/
this.approximateUserInstallCount = data.approximate_user_install_count;
} else {
this.approximateUserInstallCount ??= null;
}
if ('guild_id' in data) { if ('guild_id' in data) {
/** /**
* The id of the guild associated with this application. * The id of the guild associated with this application.

View File

@@ -45,6 +45,21 @@ class CommandInteraction extends BaseInteraction {
*/ */
this.commandGuildId = data.data.guild_id ?? null; this.commandGuildId = data.data.guild_id ?? null;
/* eslint-disable max-len */
/**
* Mapping of installation contexts that the interaction was authorized for the related user or guild ids
* @type {APIAuthorizingIntegrationOwnersMap}
* @see {@link https://discord.com/developers/docs/interactions/receiving-and-responding#interaction-object-authorizing-integration-owners-object}
*/
this.authorizingIntegrationOwners = data.authorizing_integration_owners;
/* eslint-enable max-len */
/**
* Context where the interaction was triggered from
* @type {?InteractionContextType}
*/
this.context = data.context ?? null;
/** /**
* Whether the reply to this interaction has been deferred * Whether the reply to this interaction has been deferred
* @type {boolean} * @type {boolean}

View File

@@ -26,6 +26,7 @@ const { createComponent } = require('../util/Components');
const { NonSystemMessageTypes, MaxBulkDeletableMessageAge, UndeletableMessageTypes } = require('../util/Constants'); const { NonSystemMessageTypes, MaxBulkDeletableMessageAge, UndeletableMessageTypes } = require('../util/Constants');
const MessageFlagsBitField = require('../util/MessageFlagsBitField'); const MessageFlagsBitField = require('../util/MessageFlagsBitField');
const PermissionsBitField = require('../util/PermissionsBitField'); const PermissionsBitField = require('../util/PermissionsBitField');
const { _transformAPIMessageInteractionMetadata } = require('../util/Transformers.js');
const { cleanContent, resolvePartialEmoji, transformResolved } = require('../util/Util'); const { cleanContent, resolvePartialEmoji, transformResolved } = require('../util/Util');
/** /**
@@ -383,6 +384,33 @@ class Message extends Base {
this.channel?.messages._add({ guild_id: data.message_reference?.guild_id, ...data.referenced_message }); this.channel?.messages._add({ guild_id: data.message_reference?.guild_id, ...data.referenced_message });
} }
if (data.interaction_metadata) {
/**
* Partial data of the interaction that a 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
*/
/**
* Partial data of the interaction that this message is a result of
* @type {?MessageInteractionMetadata}
*/
this.interactionMetadata = _transformAPIMessageInteractionMetadata(this.client, data.interaction_metadata);
} else {
this.interactionMetadata ??= null;
}
/** /**
* Partial data of the interaction that a message is a reply to * Partial data of the interaction that a message is a reply to
* @typedef {Object} MessageInteraction * @typedef {Object} MessageInteraction
@@ -391,6 +419,7 @@ class Message extends Base {
* @property {string} commandName The name of the interaction's application command, * @property {string} commandName The name of the interaction's application command,
* as well as the subcommand and subcommand group, where applicable * as well as the subcommand and subcommand group, where applicable
* @property {User} user The user that invoked the interaction * @property {User} user The user that invoked the interaction
* @deprecated Use {@link Message#interactionMetadata} instead.
*/ */
if (data.interaction) { if (data.interaction) {

View File

@@ -2,6 +2,7 @@
const { BaseChannel } = require('./BaseChannel'); const { BaseChannel } = require('./BaseChannel');
const { DiscordjsError, ErrorCodes } = require('../errors'); const { DiscordjsError, ErrorCodes } = require('../errors');
const PartialGroupDMMessageManager = require('../managers/PartialGroupDMMessageManager');
/** /**
* Represents a Partial Group DM Channel on Discord. * Represents a Partial Group DM Channel on Discord.
@@ -37,6 +38,12 @@ class PartialGroupDMChannel extends BaseChannel {
* @type {PartialRecipient[]} * @type {PartialRecipient[]}
*/ */
this.recipients = data.recipients; this.recipients = data.recipients;
/**
* A manager of the messages belonging to this channel
* @type {PartialGroupDMMessageManager}
*/
this.messages = new PartialGroupDMMessageManager(this);
} }
/** /**

View File

@@ -30,6 +30,16 @@
* @see {@link https://discord-api-types.dev/api/discord-api-types-v10#APIApplicationCommandOption} * @see {@link https://discord-api-types.dev/api/discord-api-types-v10#APIApplicationCommandOption}
*/ */
/**
* @external ApplicationIntegrationType
* @see {@link https://discord-api-types.dev/api/discord-api-types-v10/enum/ApplicationIntegrationType}
*/
/**
* @external APIAuthorizingIntegrationOwnersMap
* @see {@link https://discord-api-types.dev/api/discord-api-types-v10#APIAuthorizingIntegrationOwnersMap}
*/
/** /**
* @external APIAutoModerationAction * @external APIAutoModerationAction
* @see {@link https://discord-api-types.dev/api/discord-api-types-v10/interface/APIAutoModerationAction} * @see {@link https://discord-api-types.dev/api/discord-api-types-v10/interface/APIAutoModerationAction}
@@ -140,6 +150,11 @@
* @see {@link https://discord-api-types.dev/api/discord-api-types-v10/interface/APIMessageComponentEmoji} * @see {@link https://discord-api-types.dev/api/discord-api-types-v10/interface/APIMessageComponentEmoji}
*/ */
/**
* @external APIMessageInteractionMetadata
* @see {@link https://discord-api-types.dev/api/discord-api-types-v10/interface/APIMessageInteractionMetadata}
*/
/** /**
* @external APIModalInteractionResponse * @external APIModalInteractionResponse
* @see {@link https://discord-api-types.dev/api/discord-api-types-v10/interface/APIModalInteractionResponse} * @see {@link https://discord-api-types.dev/api/discord-api-types-v10/interface/APIModalInteractionResponse}
@@ -400,6 +415,11 @@
* @see {@link https://discord-api-types.dev/api/discord-api-types-v10/enum/IntegrationExpireBehavior} * @see {@link https://discord-api-types.dev/api/discord-api-types-v10/enum/IntegrationExpireBehavior}
*/ */
/**
* @external InteractionContextType
* @see {@link https://discord-api-types.dev/api/discord-api-types-v10/enum/InteractionContextType}
*/
/** /**
* @external InteractionType * @external InteractionType
* @see {@link https://discord-api-types.dev/api/discord-api-types-v10/enum/InteractionType} * @see {@link https://discord-api-types.dev/api/discord-api-types-v10/enum/InteractionType}

View File

@@ -33,4 +33,25 @@ function _transformAPIAutoModerationAction(autoModerationAction) {
}; };
} }
module.exports = { toSnakeCase, _transformAPIAutoModerationAction }; /**
* Transforms an API message interaction metadata object to a camel-cased variant.
* @param {Client} client The client
* @param {APIMessageInteractionMetadata} messageInteractionMetadata The metadata to transform
* @returns {MessageInteractionMetadata}
* @ignore
*/
function _transformAPIMessageInteractionMetadata(client, messageInteractionMetadata) {
return {
id: messageInteractionMetadata.id,
type: messageInteractionMetadata.type,
user: client.users._add(messageInteractionMetadata.user),
authorizingIntegrationOwners: messageInteractionMetadata.authorizing_integration_owners,
originalResponseMessageId: messageInteractionMetadata.original_response_message_id ?? null,
interactedMessageId: messageInteractionMetadata.interacted_message_id ?? null,
triggeringInteractionMetadata: messageInteractionMetadata.triggering_interaction_metadata
? _transformAPIMessageInteractionMetadata(messageInteractionMetadata.triggering_interaction_metadata)
: null,
};
}
module.exports = { toSnakeCase, _transformAPIAutoModerationAction, _transformAPIMessageInteractionMetadata };

View File

@@ -175,6 +175,8 @@ import {
SKUType, SKUType,
APIEntitlement, APIEntitlement,
EntitlementType, EntitlementType,
ApplicationIntegrationType,
InteractionContextType,
APIPoll, APIPoll,
PollLayoutType, PollLayoutType,
APIPollAnswer, APIPollAnswer,
@@ -182,6 +184,7 @@ import {
SelectMenuDefaultValueType, SelectMenuDefaultValueType,
InviteType, InviteType,
ReactionType, ReactionType,
APIAuthorizingIntegrationOwnersMap,
} from 'discord-api-types/v10'; } from 'discord-api-types/v10';
import { ChildProcess } from 'node:child_process'; import { ChildProcess } from 'node:child_process';
import { EventEmitter } from 'node:events'; import { EventEmitter } from 'node:events';
@@ -429,17 +432,20 @@ export abstract class Application extends Base {
export class ApplicationCommand<PermissionsFetchType = {}> extends Base { export class ApplicationCommand<PermissionsFetchType = {}> extends Base {
private constructor(client: Client<true>, data: RawApplicationCommandData, guild?: Guild, guildId?: Snowflake); private constructor(client: Client<true>, data: RawApplicationCommandData, guild?: Guild, guildId?: Snowflake);
public applicationId: Snowflake; public applicationId: Snowflake;
public contexts: InteractionContextType[] | null;
public get createdAt(): Date; public get createdAt(): Date;
public get createdTimestamp(): number; public get createdTimestamp(): number;
public defaultMemberPermissions: Readonly<PermissionsBitField> | null; public defaultMemberPermissions: Readonly<PermissionsBitField> | null;
public description: string; public description: string;
public descriptionLocalizations: LocalizationMap | null; public descriptionLocalizations: LocalizationMap | null;
public descriptionLocalized: string | null; public descriptionLocalized: string | null;
/** @deprecated Use {@link ApplicationCommand.contexts} instead */
public dmPermission: boolean | null; public dmPermission: boolean | null;
public guild: Guild | null; public guild: Guild | null;
public guildId: Snowflake | null; public guildId: Snowflake | null;
public get manager(): ApplicationCommandManager; public get manager(): ApplicationCommandManager;
public id: Snowflake; public id: Snowflake;
public integrationTypes: ApplicationIntegrationType[] | null;
public name: string; public name: string;
public nameLocalizations: LocalizationMap | null; public nameLocalizations: LocalizationMap | null;
public nameLocalized: string | null; public nameLocalized: string | null;
@@ -541,6 +547,7 @@ export type GuildCacheMessage<Cached extends CacheType> = CacheTypeReducer<
export type BooleanCache<Cached extends CacheType> = Cached extends 'cached' ? true : false; export type BooleanCache<Cached extends CacheType> = Cached extends 'cached' ? true : false;
export abstract class CommandInteraction<Cached extends CacheType = CacheType> extends BaseInteraction<Cached> { export abstract class CommandInteraction<Cached extends CacheType = CacheType> extends BaseInteraction<Cached> {
public authorizingIntegrationOwners: APIAuthorizingIntegrationOwnersMap;
public type: InteractionType.ApplicationCommand; public type: InteractionType.ApplicationCommand;
public get command(): ApplicationCommand | ApplicationCommand<{ guild: GuildResolvable }> | null; public get command(): ApplicationCommand | ApplicationCommand<{ guild: GuildResolvable }> | null;
public options: Omit< public options: Omit<
@@ -565,6 +572,7 @@ export abstract class CommandInteraction<Cached extends CacheType = CacheType> e
public commandName: string; public commandName: string;
public commandType: ApplicationCommandType; public commandType: ApplicationCommandType;
public commandGuildId: Snowflake | null; public commandGuildId: Snowflake | null;
public context: InteractionContextType | null;
public deferred: boolean; public deferred: boolean;
public ephemeral: boolean | null; public ephemeral: boolean | null;
public replied: boolean; public replied: boolean;
@@ -1073,8 +1081,10 @@ export class ClientApplication extends Application {
public cover: string | null; public cover: string | null;
public flags: Readonly<ApplicationFlagsBitField>; public flags: Readonly<ApplicationFlagsBitField>;
public approximateGuildCount: number | null; public approximateGuildCount: number | null;
public approximateUserInstallCount: number | null;
public tags: string[]; public tags: string[];
public installParams: ClientApplicationInstallParams | null; public installParams: ClientApplicationInstallParams | null;
public integrationTypesConfig: IntegrationTypesConfiguration | null;
public customInstallURL: string | null; public customInstallURL: string | null;
public owner: User | Team | null; public owner: User | Team | null;
public get partial(): boolean; public get partial(): boolean;
@@ -1932,7 +1942,7 @@ export class BaseInteraction<Cached extends CacheType = CacheType> extends Base
public type: InteractionType; public type: InteractionType;
public user: User; public user: User;
public version: number; public version: number;
public appPermissions: CacheTypeReducer<Cached, Readonly<PermissionsBitField>>; public appPermissions: Readonly<PermissionsBitField>;
public memberPermissions: CacheTypeReducer<Cached, Readonly<PermissionsBitField>>; public memberPermissions: CacheTypeReducer<Cached, Readonly<PermissionsBitField>>;
public locale: Locale; public locale: Locale;
public guildLocale: CacheTypeReducer<Cached, Locale>; public guildLocale: CacheTypeReducer<Cached, Locale>;
@@ -2150,7 +2160,9 @@ export class Message<InGuild extends boolean = boolean> extends Base {
public get guild(): If<InGuild, Guild>; public get guild(): If<InGuild, Guild>;
public get hasThread(): boolean; public get hasThread(): boolean;
public id: Snowflake; public id: Snowflake;
/** @deprecated Use {@link Message.interactionMetadata} instead. */
public interaction: MessageInteraction | null; public interaction: MessageInteraction | null;
public interactionMetadata: MessageInteractionMetadata | null;
public get member(): GuildMember | null; public get member(): GuildMember | null;
public mentions: MessageMentions<InGuild>; public mentions: MessageMentions<InGuild>;
public nonce: string | number | null; public nonce: string | number | null;
@@ -2180,23 +2192,27 @@ export class Message<InGuild extends boolean = boolean> extends Base {
public createMessageComponentCollector<ComponentType extends MessageComponentType>( public createMessageComponentCollector<ComponentType extends MessageComponentType>(
options?: MessageCollectorOptionsParams<ComponentType, InGuild>, options?: MessageCollectorOptionsParams<ComponentType, InGuild>,
): InteractionCollector<MappedInteractionTypes<InGuild>[ComponentType]>; ): InteractionCollector<MappedInteractionTypes<InGuild>[ComponentType]>;
public delete(): Promise<Message<InGuild>>; public delete(): Promise<NonPartialGroupDMChannel<Message<InGuild>>>;
public edit(content: string | MessageEditOptions | MessagePayload): Promise<Message<InGuild>>; public edit(
content: string | MessageEditOptions | MessagePayload,
): Promise<NonPartialGroupDMChannel<Message<InGuild>>>;
public equals(message: Message, rawData: unknown): boolean; public equals(message: Message, rawData: unknown): boolean;
public fetchReference(): Promise<Message<InGuild>>; public fetchReference(): Promise<NonPartialGroupDMChannel<Message<InGuild>>>;
public fetchWebhook(): Promise<Webhook>; public fetchWebhook(): Promise<Webhook>;
public crosspost(): Promise<Message<InGuild>>; public crosspost(): Promise<NonPartialGroupDMChannel<Message<InGuild>>>;
public fetch(force?: boolean): Promise<Message<InGuild>>; public fetch(force?: boolean): Promise<NonPartialGroupDMChannel<Message<InGuild>>>;
public pin(reason?: string): Promise<Message<InGuild>>; public pin(reason?: string): Promise<NonPartialGroupDMChannel<Message<InGuild>>>;
public react(emoji: EmojiIdentifierResolvable): Promise<MessageReaction>; public react(emoji: EmojiIdentifierResolvable): Promise<MessageReaction>;
public removeAttachments(): Promise<Message<InGuild>>; public removeAttachments(): Promise<NonPartialGroupDMChannel<Message<InGuild>>>;
public reply(options: string | MessagePayload | MessageReplyOptions): Promise<Message<InGuild>>; public reply(
options: string | MessagePayload | MessageReplyOptions,
): Promise<NonPartialGroupDMChannel<Message<InGuild>>>;
public resolveComponent(customId: string): MessageActionRowComponent | null; public resolveComponent(customId: string): MessageActionRowComponent | null;
public startThread(options: StartThreadOptions): Promise<PublicThreadChannel<false>>; public startThread(options: StartThreadOptions): Promise<PublicThreadChannel<false>>;
public suppressEmbeds(suppress?: boolean): Promise<Message<InGuild>>; public suppressEmbeds(suppress?: boolean): Promise<NonPartialGroupDMChannel<Message<InGuild>>>;
public toJSON(): unknown; public toJSON(): unknown;
public toString(): string; public toString(): string;
public unpin(reason?: string): Promise<Message<InGuild>>; public unpin(reason?: string): Promise<NonPartialGroupDMChannel<Message<InGuild>>>;
public inGuild(): this is Message<true>; public inGuild(): this is Message<true>;
} }
@@ -2540,6 +2556,7 @@ export class PartialGroupDMChannel extends BaseChannel {
public name: string | null; public name: string | null;
public icon: string | null; public icon: string | null;
public recipients: PartialRecipient[]; public recipients: PartialRecipient[];
public messages: PartialGroupDMMessageManager;
public iconURL(options?: ImageURLOptions): string | null; public iconURL(options?: ImageURLOptions): string | null;
public toString(): ChannelMention; public toString(): ChannelMention;
} }
@@ -4501,6 +4518,10 @@ export class DMMessageManager extends MessageManager {
public channel: DMChannel; public channel: DMChannel;
} }
export class PartialGroupDMMessageManager extends MessageManager {
public channel: PartialGroupDMChannel;
}
export class GuildMessageManager extends MessageManager<true> { export class GuildMessageManager extends MessageManager<true> {
public channel: GuildTextBasedChannel; public channel: GuildTextBasedChannel;
public crosspost(message: MessageResolvable): Promise<Message<true>>; public crosspost(message: MessageResolvable): Promise<Message<true>>;
@@ -4755,6 +4776,8 @@ export interface BaseApplicationCommandData {
dmPermission?: boolean; dmPermission?: boolean;
defaultMemberPermissions?: PermissionResolvable | null; defaultMemberPermissions?: PermissionResolvable | null;
nsfw?: boolean; nsfw?: boolean;
contexts?: readonly InteractionContextType[];
integrationTypes?: readonly ApplicationIntegrationType[];
} }
export interface AttachmentData { export interface AttachmentData {
@@ -5247,6 +5270,10 @@ export interface GuildMembersChunk {
nonce: string | undefined; nonce: string | undefined;
} }
type NonPartialGroupDMChannel<Structure extends { channel: Channel }> = Structure & {
channel: Exclude<Structure['channel'], PartialGroupDMChannel>;
};
export interface ClientEvents { export interface ClientEvents {
applicationCommandPermissionsUpdate: [data: ApplicationCommandPermissionsUpdateData]; applicationCommandPermissionsUpdate: [data: ApplicationCommandPermissionsUpdateData];
autoModerationActionExecution: [autoModerationActionExecution: AutoModerationActionExecution]; autoModerationActionExecution: [autoModerationActionExecution: AutoModerationActionExecution];
@@ -5289,17 +5316,17 @@ export interface ClientEvents {
guildUpdate: [oldGuild: Guild, newGuild: Guild]; guildUpdate: [oldGuild: Guild, newGuild: Guild];
inviteCreate: [invite: Invite]; inviteCreate: [invite: Invite];
inviteDelete: [invite: Invite]; inviteDelete: [invite: Invite];
messageCreate: [message: Message]; messageCreate: [message: NonPartialGroupDMChannel<Message>];
messageDelete: [message: Message | PartialMessage]; messageDelete: [message: NonPartialGroupDMChannel<Message | PartialMessage>];
messagePollVoteAdd: [pollAnswer: PollAnswer, userId: Snowflake]; messagePollVoteAdd: [pollAnswer: PollAnswer, userId: Snowflake];
messagePollVoteRemove: [pollAnswer: PollAnswer, userId: Snowflake]; messagePollVoteRemove: [pollAnswer: PollAnswer, userId: Snowflake];
messageReactionRemoveAll: [ messageReactionRemoveAll: [
message: Message | PartialMessage, message: NonPartialGroupDMChannel<Message | PartialMessage>,
reactions: ReadonlyCollection<string | Snowflake, MessageReaction>, reactions: ReadonlyCollection<string | Snowflake, MessageReaction>,
]; ];
messageReactionRemoveEmoji: [reaction: MessageReaction | PartialMessageReaction]; messageReactionRemoveEmoji: [reaction: MessageReaction | PartialMessageReaction];
messageDeleteBulk: [ messageDeleteBulk: [
messages: ReadonlyCollection<Snowflake, Message | PartialMessage>, messages: ReadonlyCollection<Snowflake, NonPartialGroupDMChannel<Message | PartialMessage>>,
channel: GuildTextBasedChannel, channel: GuildTextBasedChannel,
]; ];
messageReactionAdd: [ messageReactionAdd: [
@@ -6221,6 +6248,16 @@ export interface IntegrationAccount {
export type IntegrationType = 'twitch' | 'youtube' | 'discord' | 'guild_subscription'; export type IntegrationType = 'twitch' | 'youtube' | 'discord' | 'guild_subscription';
export type IntegrationTypesConfigurationParameters = ClientApplicationInstallParams;
export interface IntegrationTypesConfigurationContext {
oauth2InstallParams: IntegrationTypesConfigurationParameters | null;
}
export type IntegrationTypesConfiguration = Partial<
Record<ApplicationIntegrationType, IntegrationTypesConfigurationContext>
>;
export type CollectedInteraction<Cached extends CacheType = CacheType> = export type CollectedInteraction<Cached extends CacheType = CacheType> =
| StringSelectMenuInteraction<Cached> | StringSelectMenuInteraction<Cached>
| UserSelectMenuInteraction<Cached> | UserSelectMenuInteraction<Cached>
@@ -6369,6 +6406,16 @@ export interface MessageComponentCollectorOptions<Interaction extends CollectedM
export interface MessageChannelComponentCollectorOptions<Interaction extends CollectedMessageInteraction> export interface MessageChannelComponentCollectorOptions<Interaction extends CollectedMessageInteraction>
extends Omit<InteractionCollectorOptions<Interaction>, 'channel' | 'guild' | 'interactionType'> {} 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 { export interface MessageInteraction {
id: Snowflake; id: Snowflake;
type: InteractionType; type: InteractionType;
@@ -6829,10 +6876,7 @@ export type Channel =
| ForumChannel | ForumChannel
| MediaChannel; | MediaChannel;
export type TextBasedChannel = Exclude< export type TextBasedChannel = Exclude<Extract<Channel, { type: TextChannelType }>, ForumChannel | MediaChannel>;
Extract<Channel, { type: TextChannelType }>,
PartialGroupDMChannel | ForumChannel | MediaChannel
>;
export type TextBasedChannels = TextBasedChannel; export type TextBasedChannels = TextBasedChannel;

View File

@@ -452,7 +452,7 @@ client.on('messageCreate', async message => {
expectType<Collection<Snowflake, GuildMember>>(message.mentions.members); expectType<Collection<Snowflake, GuildMember>>(message.mentions.members);
} }
expectType<TextBasedChannel>(message.channel); expectType<Exclude<TextBasedChannel, PartialGroupDMChannel>>(message.channel);
expectNotType<GuildTextBasedChannel>(message.channel); expectNotType<GuildTextBasedChannel>(message.channel);
// @ts-expect-error // @ts-expect-error
@@ -1624,7 +1624,7 @@ declare const guildChannelManager: GuildChannelManager;
expectType<Promise<Collection<Snowflake, Message>>>(messages.fetchPinned()); expectType<Promise<Collection<Snowflake, Message>>>(messages.fetchPinned());
expectType<Guild | null>(message.guild); expectType<Guild | null>(message.guild);
expectType<Snowflake | null>(message.guildId); expectType<Snowflake | null>(message.guildId);
expectType<DMChannel | GuildTextBasedChannel>(message.channel.messages.channel); expectType<DMChannel | PartialGroupDMChannel | GuildTextBasedChannel>(message.channel.messages.channel);
expectType<MessageMentions>(message.mentions); expectType<MessageMentions>(message.mentions);
expectType<Guild | null>(message.mentions.guild); expectType<Guild | null>(message.mentions.guild);
expectType<Collection<Snowflake, GuildMember> | null>(message.mentions.members); expectType<Collection<Snowflake, GuildMember> | null>(message.mentions.members);
@@ -2209,6 +2209,7 @@ expectType<TextBasedChannel>(TextBasedChannel);
expectType< expectType<
| ChannelType.GuildText | ChannelType.GuildText
| ChannelType.DM | ChannelType.DM
| ChannelType.GroupDM
| ChannelType.GuildAnnouncement | ChannelType.GuildAnnouncement
| ChannelType.GuildVoice | ChannelType.GuildVoice
| ChannelType.GuildStageVoice | ChannelType.GuildStageVoice