feat: Auto Moderation (#7938)

* feat: initial AutoMod commit

* types: Typo in class name

Co-authored-by: Jonathan <54381371+axisiscool@users.noreply.github.com>

* refactor: move things around

* refactor: remove undocumented property

* chore: add new intents to issue form

* feat: add initial basic manager

* feat(AutoModRule): add new properties

* feat: add events

* feat(GuildAuditLog): cache rules

* refactor: move JSDoc to where it is actually used

* refactor(AutoModRule): add `_patch()` method

* feat(AutoModRuleManager): add resolvers

* feat(Sweepers): add new manager

* types: nullify first parameter of `autoModerationRuleUpdate`

* types: add manager to `Caches`

* docs(AutoModRule): update `metadata` docstring

* feat: add execution event

* fix(AutoModActionExecution): export class

* refactor(AutoModRule): `triggerType` is not modifiable

* docs(AutoModRule): link class

* feat: add trigger metadata definitions

* docs(AutoModRule): typos

* feat(AutoModRule): action metadata

* types: Proper casing of name

Co-authored-by: MateoDeveloper <79017590+Mateo-tem@users.noreply.github.com>

* refactor: only patch data if exists

* types: `preset` is an array

* types(AutoModRuleActionMetadata): nullify all

* feat(AutoModRuleManager): add `fetch()`

* docs(AutoModRule): tweak some wording

* docs(AutoModRule): use "array" over "list"

* docs(AutoModRuleResolvable): fix union

* types: adjust some names

* feat(AutoModRuleManager): add `create()`

* feat(AutoModRuleManager): add `delete()`

* refactor: prefer full auto moderation name

* docs(AutoModerationRuleManager): fix a fetch example

* refactor(Sweepers): alphabetise methods

* chore: remove testing

* fix(AutoModerationRuleCreateOptions): add `reason`

* fix: typo for `presets`

* fix(AutoModerationRuleCreateOptions): `actions` is required

* fix(AutoModerationRuleManager): handle properties that are unrequired

* feat(AutoModerationRuleManager): add `edit()`

* feat(GuildAuditLogsEntry): add auto moderation rules

* refactor: prefer "AutoModerationActionExecutionAction"

* refactor: annotate todos and doc fixes

* feat(AutoModerationRule): add guild getter

* docs(AutoModerationRule): rule -> auto moderation rule

* docs(AutoModerationRuleEditOptions): `eventType` is optional

* feat(AutoModerationRule): add helpers

* docs: random string updates

* chore: add TODOs

* feat(AutoModerationActionExecution): add helpers

* feat: support role and channel resolvables

* chore: high priority todo to keep me in solitary

* refactor(AutoModerationActionMetadataOptions): allow resolvables

* chore: tidy up from merge

* docs(AutoModerationRule): document extension

* feat: export `AutoModerationRuleManager`

* chore(ActionsManager): add new actions

* chore: add to websocket index

* refactor(AutoModerationActionExecution): send the guild across

* docs(AutoModerationActionExecution): typo

* docs(AutoModerationRule): deduplicate a word

* docs(Guild): dot

* test: add some basic tests

* docs(AutoModerationRuleManager): fetch is optional

* docs(AutoModerationActionExecution): prefer non-links

* types: `presets` is an array of numbers

* docs(AutoModerationRuleEditOptions): `name` is optional

* docs(AutoModerationRule): fix type for `exemptChannels`

* docs(AutoModerationRuleUpdateAction): remove "object"

* feat: add `allow_list`

* fix(GuildAuditLogsEntry): pass guild

* docs(AutoModerationRuleManager): correct fetch example

* chore: prettier

* refactor: remove unneeded optional chaining operator

* feat: add mention limit

* docs(AutoModerationRuleManager): document new requirement

* refactor: conform to message content intent

* docs: document permission for event

* docs: refactor intent message

* docs: dot

* docs: remove string in link

* refactor: document upstream changes

* fix(AutoModerationRuleDelete): Correct event fire

Co-authored-by: GoldenAngel <50855202+GoldenAngel2@users.noreply.github.com>

* feat(AutoModerationRule): Add `setMentionTotalLimit()` helper method

* feat(AuditLogEntries): add new extra fields

* types: add `guild` in constructors

* types: update typings

* refactor(AutoModerationRuleManager): `&&` shorthand

* types: remove leftover type

* chore: types

* docs: update API types

* docs: Tweak guild wording

Co-authored-by: Aura Román <kyradiscord@gmail.com>

* feat: add regular expression matching

* docs: update `allowList` wording

* refactor: deduplicate `guildId`

Co-authored-by: Jonathan <54381371+axisiscool@users.noreply.github.com>
Co-authored-by: MateoDeveloper <79017590+Mateo-tem@users.noreply.github.com>
Co-authored-by: GoldenAngel <50855202+GoldenAngel2@users.noreply.github.com>
Co-authored-by: Aura Román <kyradiscord@gmail.com>
This commit is contained in:
Jiralite 2022-11-19 22:06:13 +00:00 committed by GitHub
parent 153d2403ad
commit fd4ba5eaba
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
24 changed files with 1072 additions and 3 deletions

View file

@ -132,6 +132,8 @@ body:
- DirectMessageTyping
- MessageContent
- GuildScheduledEvents
- AutoModerationConfiguration
- AutoModerationExecution
multiple: true
validations:
required: true

View file

@ -5,6 +5,10 @@ class ActionsManager {
this.client = client;
this.register(require('./ApplicationCommandPermissionsUpdate'));
this.register(require('./AutoModerationActionExecution'));
this.register(require('./AutoModerationRuleCreate'));
this.register(require('./AutoModerationRuleDelete'));
this.register(require('./AutoModerationRuleUpdate'));
this.register(require('./ChannelCreate'));
this.register(require('./ChannelDelete'));
this.register(require('./ChannelUpdate'));

View file

@ -0,0 +1,26 @@
'use strict';
const Action = require('./Action');
const AutoModerationActionExecution = require('../../structures/AutoModerationActionExecution');
const Events = require('../../util/Events');
class AutoModerationActionExecutionAction extends Action {
handle(data) {
const { client } = this;
const guild = client.guilds.cache.get(data.guild_id);
if (guild) {
/**
* Emitted whenever an auto moderation rule is triggered.
* <info>This event requires the {@link PermissionFlagsBits.ManageGuild} permission.</info>
* @event Client#autoModerationActionExecution
* @param {AutoModerationActionExecution} autoModerationActionExecution The data of the execution
*/
client.emit(Events.AutoModerationActionExecution, new AutoModerationActionExecution(data, guild));
}
return {};
}
}
module.exports = AutoModerationActionExecutionAction;

View file

@ -0,0 +1,27 @@
'use strict';
const Action = require('./Action');
const Events = require('../../util/Events');
class AutoModerationRuleCreateAction extends Action {
handle(data) {
const { client } = this;
const guild = client.guilds.cache.get(data.guild_id);
if (guild) {
const autoModerationRule = guild.autoModerationRules._add(data);
/**
* Emitted whenever an auto moderation rule is created.
* <info>This event requires the {@link PermissionFlagsBits.ManageGuild} permission.</info>
* @event Client#autoModerationRuleCreate
* @param {AutoModerationRule} autoModerationRule The created auto moderation rule
*/
client.emit(Events.AutoModerationRuleCreate, autoModerationRule);
}
return {};
}
}
module.exports = AutoModerationRuleCreateAction;

View file

@ -0,0 +1,31 @@
'use strict';
const Action = require('./Action');
const Events = require('../../util/Events');
class AutoModerationRuleDeleteAction extends Action {
handle(data) {
const { client } = this;
const guild = client.guilds.cache.get(data.guild_id);
if (guild) {
const autoModerationRule = guild.autoModerationRules.cache.get(data.id);
if (autoModerationRule) {
guild.autoModerationRules.cache.delete(autoModerationRule.id);
/**
* Emitted whenever an auto moderation rule is deleted.
* <info>This event requires the {@link PermissionFlagsBits.ManageGuild} permission.</info>
* @event Client#autoModerationRuleDelete
* @param {AutoModerationRule} autoModerationRule The deleted auto moderation rule
*/
client.emit(Events.AutoModerationRuleDelete, autoModerationRule);
}
}
return {};
}
}
module.exports = AutoModerationRuleDeleteAction;

View file

@ -0,0 +1,29 @@
'use strict';
const Action = require('./Action');
const Events = require('../../util/Events');
class AutoModerationRuleUpdateAction extends Action {
handle(data) {
const { client } = this;
const guild = client.guilds.cache.get(data.guild_id);
if (guild) {
const oldAutoModerationRule = guild.autoModerationRules.cache.get(data.id)?._clone() ?? null;
const newAutoModerationRule = guild.autoModerationRules._add(data);
/**
* Emitted whenever an auto moderation rule gets updated.
* <info>This event requires the {@link PermissionFlagsBits.ManageGuild} permission.</info>
* @event Client#autoModerationRuleUpdate
* @param {?AutoModerationRule} oldAutoModerationRule The auto moderation rule before the update
* @param {AutoModerationRule} newAutoModerationRule The auto moderation rule after the update
*/
client.emit(Events.AutoModerationRuleUpdate, oldAutoModerationRule, newAutoModerationRule);
}
return {};
}
}
module.exports = AutoModerationRuleUpdateAction;

View file

@ -0,0 +1,5 @@
'use strict';
module.exports = (client, packet) => {
client.actions.AutoModerationActionExecution.handle(packet.d);
};

View file

@ -0,0 +1,5 @@
'use strict';
module.exports = (client, packet) => {
client.actions.AutoModerationRuleCreate.handle(packet.d);
};

View file

@ -0,0 +1,5 @@
'use strict';
module.exports = (client, packet) => {
client.actions.AutoModerationRuleDelete.handle(packet.d);
};

View file

@ -0,0 +1,5 @@
'use strict';
module.exports = (client, packet) => {
client.actions.AutoModerationRuleUpdate.handle(packet.d);
};

View file

@ -2,6 +2,10 @@
const handlers = Object.fromEntries([
['APPLICATION_COMMAND_PERMISSIONS_UPDATE', require('./APPLICATION_COMMAND_PERMISSIONS_UPDATE')],
['AUTO_MODERATION_ACTION_EXECUTION', require('./AUTO_MODERATION_ACTION_EXECUTION')],
['AUTO_MODERATION_RULE_CREATE', require('./AUTO_MODERATION_RULE_CREATE')],
['AUTO_MODERATION_RULE_DELETE', require('./AUTO_MODERATION_RULE_DELETE')],
['AUTO_MODERATION_RULE_UPDATE', require('./AUTO_MODERATION_RULE_UPDATE')],
['CHANNEL_CREATE', require('./CHANNEL_CREATE')],
['CHANNEL_DELETE', require('./CHANNEL_DELETE')],
['CHANNEL_PINS_UPDATE', require('./CHANNEL_PINS_UPDATE')],

View file

@ -48,6 +48,7 @@ exports.version = require('../package.json').version;
// Managers
exports.ApplicationCommandManager = require('./managers/ApplicationCommandManager');
exports.ApplicationCommandPermissionsManager = require('./managers/ApplicationCommandPermissionsManager');
exports.AutoModerationRuleManager = require('./managers/AutoModerationRuleManager');
exports.BaseGuildEmojiManager = require('./managers/BaseGuildEmojiManager');
exports.CachedManager = require('./managers/CachedManager');
exports.ChannelManager = require('./managers/ChannelManager');
@ -88,6 +89,8 @@ exports.AnonymousGuild = require('./structures/AnonymousGuild');
exports.Application = require('./structures/interfaces/Application');
exports.ApplicationCommand = require('./structures/ApplicationCommand');
exports.AutocompleteInteraction = require('./structures/AutocompleteInteraction');
exports.AutoModerationActionExecution = require('./structures/AutoModerationActionExecution');
exports.AutoModerationRule = require('./structures/AutoModerationRule');
exports.Base = require('./structures/Base');
exports.BaseGuild = require('./structures/BaseGuild');
exports.BaseGuildEmoji = require('./structures/BaseGuildEmoji');

View file

@ -0,0 +1,276 @@
'use strict';
const { Collection } = require('@discordjs/collection');
const { Routes } = require('discord-api-types/v10');
const CachedManager = require('./CachedManager');
const AutoModerationRule = require('../structures/AutoModerationRule');
/**
* Manages API methods for auto moderation rules and stores their cache.
* @extends {CachedManager}
*/
class AutoModerationRuleManager extends CachedManager {
constructor(guild, iterable) {
super(guild.client, AutoModerationRule, iterable);
/**
* The guild this manager belongs to.
* @type {Guild}
*/
this.guild = guild;
}
_add(data, cache) {
return super._add(data, cache, { extras: [this.guild] });
}
/**
* Options used to set the trigger metadata of an auto moderation rule.
* @typedef {Object} AutoModerationTriggerMetadataOptions
* @property {string[]} [keywordFilter] The substrings that will be searched for in the content
* @property {string[]} [regexPatterns] The regular expression patterns which will be matched against the content
* <info>Only Rust-flavored regular expressions are supported.</info>
* @property {AutoModerationRuleKeywordPresetType[]} [presets]
* The internally pre-defined wordsets which will be searched for in the content
* @property {string[]} [allowList] The substrings that will be exempt from triggering
* {@link AutoModerationRuleTriggerType.Keyword} and {@link AutoModerationRuleTriggerType.KeywordPreset}
* @property {?number} [mentionTotalLimit] The total number of role & user mentions allowed per message
*/
/**
* Options used to set the actions of an auto moderation rule.
* @typedef {Object} AutoModerationActionOptions
* @property {AutoModerationActionType} type The type of this auto moderation rule action
* @property {AutoModerationActionMetadataOptions} [metadata] Additional metadata needed during execution
* <info>This property is required if using a `type` of
* {@link AutoModerationActionType.SendAlertMessage} or {@link AutoModerationActionType.Timeout}.</info>
*/
/**
* Options used to set the metadata of an auto moderation rule action.
* @typedef {Object} AutoModerationActionMetadataOptions
* @property {GuildTextChannelResolvable|ThreadChannel} [channel] The channel to which content will be logged
* @property {number} [durationSeconds] The timeout duration in seconds
*/
/**
* Options used to create an auto moderation rule.
* @typedef {Object} AutoModerationRuleCreateOptions
* @property {string} name The name of the auto moderation rule
* @property {AutoModerationRuleEventType} eventType The event type of the auto moderation rule
* @property {AutoModerationRuleTriggerType} triggerType The trigger type of the auto moderation rule
* @property {AutoModerationTriggerMetadataOptions} [triggerMetadata] The trigger metadata of the auto moderation rule
* <info>This property is required if using a `triggerType` of
* {@link AutoModerationRuleTriggerType.Keyword}, {@link AutoModerationRuleTriggerType.KeywordPreset},
* or {@link AutoModerationRuleTriggerType.MentionSpam}.</info>
* @property {AutoModerationActionOptions[]} actions
* The actions that will execute when the auto moderation rule is triggered
* @property {boolean} [enabled] Whether the auto moderation rule should be enabled
* @property {Collection<Snowflake, Role>|RoleResolvable[]} [exemptRoles]
* The roles that should not be affected by the auto moderation rule
* @property {Collection<Snowflake, GuildChannel|ThreadChannel>|GuildChannelResolvable[]} [exemptChannels]
* The channels that should not be affected by the auto moderation rule
* @property {string} [reason] The reason for creating the auto moderation rule
*/
/**
* Creates a new auto moderation rule.
* @param {AutoModerationRuleCreateOptions} options Options for creating the auto moderation rule
* @returns {Promise<AutoModerationRule>}
*/
async create({
name,
eventType,
triggerType,
triggerMetadata,
actions,
enabled,
exemptRoles,
exemptChannels,
reason,
}) {
const data = await this.client.rest.post(Routes.guildAutoModerationRules(this.guild.id), {
body: {
name,
event_type: eventType,
trigger_type: triggerType,
trigger_metadata: triggerMetadata && {
keyword_filter: triggerMetadata.keywordFilter,
regex_patterns: triggerMetadata.regexPatterns,
presets: triggerMetadata.presets,
allow_list: triggerMetadata.allowList,
mention_total_limit: triggerMetadata.mentionTotalLimit,
},
actions: actions.map(action => ({
type: action.type,
metadata: {
duration_seconds: action.metadata?.durationSeconds,
channel_id: action.metadata?.channel && this.guild.channels.resolveId(action.metadata.channel),
},
})),
enabled,
exempt_roles: exemptRoles?.map(exemptRole => this.guild.roles.resolveId(exemptRole)),
exempt_channels: exemptChannels?.map(exemptChannel => this.guild.channels.resolveId(exemptChannel)),
},
reason,
});
return this._add(data);
}
/**
* Options used to edit an auto moderation rule.
* @typedef {Object} AutoModerationRuleEditOptions
* @property {string} [name] The name of the auto moderation rule
* @property {AutoModerationRuleEventType} [eventType] The event type of the auto moderation rule
* @property {AutoModerationTriggerMetadataOptions} [triggerMetadata] The trigger metadata of the auto moderation rule
* @property {AutoModerationActionOptions[]} [actions]
* The actions that will execute when the auto moderation rule is triggered
* @property {boolean} [enabled] Whether the auto moderation rule should be enabled
* @property {Collection<Snowflake, Role>|RoleResolvable[]} [exemptRoles]
* The roles that should not be affected by the auto moderation rule
* @property {Collection<Snowflake, GuildChannel|ThreadChannel>|GuildChannelResolvable[]} [exemptChannels]
* The channels that should not be affected by the auto moderation rule
* @property {string} [reason] The reason for creating the auto moderation rule
*/
/**
* Edits an auto moderation rule.
* @param {AutoModerationRuleResolvable} autoModerationRule The auto moderation rule to edit
* @param {AutoModerationRuleEditOptions} options Options for editing the auto moderation rule
* @returns {Promise<AutoModerationRule>}
*/
async edit(
autoModerationRule,
{ name, eventType, triggerMetadata, actions, enabled, exemptRoles, exemptChannels, reason },
) {
const autoModerationRuleId = this.resolveId(autoModerationRule);
const data = await this.client.rest.patch(Routes.guildAutoModerationRule(this.guild.id, autoModerationRuleId), {
body: {
name,
event_type: eventType,
trigger_metadata: triggerMetadata && {
keyword_filter: triggerMetadata.keywordFilter,
regex_patterns: triggerMetadata.regexPatterns,
presets: triggerMetadata.presets,
allow_list: triggerMetadata.allowList,
mention_total_limit: triggerMetadata.mentionTotalLimit,
},
actions: actions?.map(action => ({
type: action.type,
metadata: {
duration_seconds: action.metadata?.durationSeconds,
channel_id: action.metadata?.channel && this.guild.channels.resolveId(action.metadata.channel),
},
})),
enabled,
exempt_roles: exemptRoles?.map(exemptRole => this.guild.roles.resolveId(exemptRole)),
exempt_channels: exemptChannels?.map(exemptChannel => this.guild.channels.resolveId(exemptChannel)),
},
reason,
});
return this._add(data);
}
/**
* Data that can be resolved to give an AutoModerationRule object. This can be:
* * An AutoModerationRule
* * A Snowflake
* @typedef {AutoModerationRule|Snowflake} AutoModerationRuleResolvable
*/
/**
* Options used to fetch a single auto moderation rule from a guild.
* @typedef {BaseFetchOptions} FetchAutoModerationRuleOptions
* @property {AutoModerationRuleResolvable} autoModerationRule The auto moderation rule to fetch
*/
/**
* Options used to fetch all auto moderation rules from a guild.
* @typedef {Object} FetchAutoModerationRulesOptions
* @property {boolean} [cache] Whether to cache the fetched auto moderation rules
*/
/**
* Fetches auto moderation rules from Discord.
* @param {AutoModerationRuleResolvable|FetchAutoModerationRuleOptions|FetchAutoModerationRulesOptions} [options]
* Options for fetching auto moderation rule(s)
* @returns {Promise<AutoModerationRule|Collection<Snowflake, AutoModerationRule>>}
* @example
* // Fetch all auto moderation rules from a guild without caching
* guild.autoModerationRules.fetch({ cache: false })
* .then(console.log)
* .catch(console.error);
* @example
* // Fetch a single auto moderation rule
* guild.autoModerationRules.fetch('979083472868098119')
* .then(console.log)
* .catch(console.error);
* @example
* // Fetch a single auto moderation rule without checking cache and without caching
* guild.autoModerationRules.fetch({ autoModerationRule: '979083472868098119', cache: false, force: true })
* .then(console.log)
* .catch(console.error)
*/
fetch(options) {
if (!options) return this._fetchMany();
const { autoModerationRule, cache, force } = options;
const resolvedAutoModerationRule = this.resolveId(autoModerationRule ?? options);
if (resolvedAutoModerationRule) {
return this._fetchSingle({ autoModerationRule: resolvedAutoModerationRule, cache, force });
}
return this._fetchMany(options);
}
async _fetchSingle({ autoModerationRule, cache, force = false }) {
if (!force) {
const existing = this.cache.get(autoModerationRule);
if (existing) return existing;
}
const data = await this.client.rest.get(Routes.guildAutoModerationRule(this.guild.id, autoModerationRule));
return this._add(data, cache);
}
async _fetchMany(options = {}) {
const data = await this.client.rest.get(Routes.guildAutoModerationRules(this.guild.id));
return data.reduce(
(col, autoModerationRule) => col.set(autoModerationRule.id, this._add(autoModerationRule, options.cache)),
new Collection(),
);
}
/**
* Deletes an auto moderation rule.
* @param {AutoModerationRuleResolvable} autoModerationRule The auto moderation rule to delete
* @param {string} [reason] The reason for deleting the auto moderation rule
* @returns {Promise<void>}
*/
async delete(autoModerationRule, reason) {
const autoModerationRuleId = this.resolveId(autoModerationRule);
await this.client.rest.delete(Routes.guildAutoModerationRule(this.guild.id, autoModerationRuleId), { reason });
}
/**
* Resolves an {@link AutoModerationRuleResolvable} to an {@link AutoModerationRule} object.
* @method resolve
* @memberof AutoModerationRuleManager
* @instance
* @param {AutoModerationRuleResolvable} autoModerationRule The AutoModerationRule resolvable to resolve
* @returns {?AutoModerationRule}
*/
/**
* Resolves an {@link AutoModerationRuleResolvable} to a {@link AutoModerationRule} id.
* @method resolveId
* @memberof AutoModerationRuleManager
* @instance
* @param {AutoModerationRuleResolvable} autoModerationRule The AutoModerationRule resolvable to resolve
* @returns {?Snowflake}
*/
}
module.exports = AutoModerationRuleManager;

View file

@ -0,0 +1,87 @@
'use strict';
/**
* Represents the structure of an executed action when an {@link AutoModerationRule} is triggered.
*/
class AutoModerationActionExecution {
constructor(data, guild) {
/**
* The guild where this action was executed from.
* @type {Guild}
*/
this.guild = guild;
/**
* The action that was executed.
* @type {AutoModerationAction}
*/
this.action = data.action;
/**
* The id of the auto moderation rule this action belongs to.
* @type {Snowflake}
*/
this.ruleId = data.rule_id;
/**
* The trigger type of the auto moderation rule which was triggered.
* @type {AutoModerationRuleTriggerType}
*/
this.ruleTriggerType = data.rule_trigger_type;
/**
* The id of the user that triggered this action.
* @type {Snowflake}
*/
this.userId = data.user_id;
/**
* The id of the channel where this action was triggered from.
* @type {?Snowflake}
*/
this.channelId = data.channel_id ?? null;
/**
* The id of the message that triggered this action.
* @type {?Snowflake}
* <info>This will not be present if the message was blocked or the content was not part of any message.</info>
*/
this.messageId = data.message_id ?? null;
/**
* The id of any system auto moderation messages posted as a result of this action.
* @type {?Snowflake}
*/
this.alertSystemMessageId = data.alert_system_message_id ?? null;
/**
* The content that triggered this action.
* <info>This property requires the {@link GatewayIntentBits.MessageContent} privileged gateway intent.</info>
* @type {string}
*/
this.content = data.content;
/**
* The word or phrase configured in the rule that triggered this action.
* @type {?string}
*/
this.matchedKeyword = data.matched_keyword ?? null;
/**
* The substring in content that triggered this action.
* @type {?string}
*/
this.matchedContent = data.matched_content ?? null;
}
/**
* The auto moderation rule this action belongs to.
* @type {?AutoModerationRule}
* @readonly
*/
get autoModerationRule() {
return this.guild.autoModerationRules.cache.get(this.ruleId) ?? null;
}
}
module.exports = AutoModerationActionExecution;

View file

@ -0,0 +1,273 @@
'use strict';
const { Collection } = require('@discordjs/collection');
const Base = require('./Base');
/**
* Represents an auto moderation rule.
* @extends {Base}
*/
class AutoModerationRule extends Base {
constructor(client, data, guild) {
super(client);
/**
* The id of this auto moderation rule.
* @type {Snowflake}
*/
this.id = data.id;
/**
* The guild this auto moderation rule is for.
* @type {Guild}
*/
this.guild = guild;
/**
* The user that created this auto moderation rule.
* @type {Snowflake}
*/
this.creatorId = data.creator_id;
/**
* The trigger type of this auto moderation rule.
* @type {AutoModerationRuleTriggerType}
*/
this.triggerType = data.trigger_type;
this._patch(data);
}
_patch(data) {
if ('name' in data) {
/**
* The name of this auto moderation rule.
* @type {string}
*/
this.name = data.name;
}
if ('event_type' in data) {
/**
* The event type of this auto moderation rule.
* @type {AutoModerationRuleEventType}
*/
this.eventType = data.event_type;
}
if ('trigger_metadata' in data) {
/**
* Additional data used to determine whether an auto moderation rule should be triggered.
* @typedef {Object} AutoModerationTriggerMetadata
* @property {string[]} keywordFilter The substrings that will be searched for in the content
* @property {string[]} regexPatterns The regular expression patterns which will be matched against the content
* <info>Only Rust-flavored regular expressions are supported.</info>
* @property {AutoModerationRuleKeywordPresetType[]} presets
* The internally pre-defined wordsets which will be searched for in the content
* @property {string[]} allowList The substrings that will be exempt from triggering
* {@link AutoModerationRuleTriggerType.Keyword} and {@link AutoModerationRuleTriggerType.KeywordPreset}
* @property {?number} mentionTotalLimit The total number of role & user mentions allowed per message
*/
/**
* The trigger metadata of the rule.
* @type {AutoModerationTriggerMetadata}
*/
this.triggerMetadata = {
keywordFilter: data.trigger_metadata.keyword_filter ?? [],
regexPatterns: data.trigger_metadata.regex_patterns ?? [],
presets: data.trigger_metadata.presets ?? [],
allowList: data.trigger_metadata.allow_list ?? [],
mentionTotalLimit: data.trigger_metadata.mention_total_limit ?? null,
};
}
if ('actions' in data) {
/**
* An object containing information about an auto moderation rule action.
* @typedef {Object} AutoModerationAction
* @property {AutoModerationActionType} type The type of this auto moderation rule action
* @property {AutoModerationActionMetadata} metadata Additional metadata needed during execution
*/
/**
* Additional data used when an auto moderation rule is executed.
* @typedef {Object} AutoModerationActionMetadata
* @property {?Snowflake} channelId The id of the channel to which content will be logged
* @property {?number} durationSeconds The timeout duration in seconds
*/
/**
* The actions of this auto moderation rule.
* @type {AutoModerationAction[]}
*/
this.actions = data.actions.map(action => ({
type: action.type,
metadata: {
durationSeconds: action.metadata.duration_seconds ?? null,
channelId: action.metadata.channel_id ?? null,
},
}));
}
if ('enabled' in data) {
/**
* Whether this auto moderation rule is enabled.
* @type {boolean}
*/
this.enabled = data.enabled;
}
if ('exempt_roles' in data) {
/**
* The roles exempt by this auto moderation rule.
* @type {Collection<Snowflake, Role>}
*/
this.exemptRoles = new Collection(
data.exempt_roles.map(exemptRole => [exemptRole, this.guild.roles.cache.get(exemptRole)]),
);
}
if ('exempt_channels' in data) {
/**
* The channels exempt by this auto moderation rule.
* @type {Collection<Snowflake, GuildChannel|ThreadChannel>}
*/
this.exemptChannels = new Collection(
data.exempt_channels.map(exemptChannel => [exemptChannel, this.guild.channels.cache.get(exemptChannel)]),
);
}
}
/**
* Edits this auto moderation rule.
* @param {AutoModerationRuleEditOptions} options Options for editing this auto moderation rule
* @returns {Promise<AutoModerationRule>}
*/
edit(options) {
return this.guild.autoModerationRules.edit(this.id, options);
}
/**
* Deletes this auto moderation rule.
* @param {string} [reason] The reason for deleting this auto moderation rule
* @returns {Promise<void>}
*/
delete(reason) {
return this.guild.autoModerationRules.delete(this.id, reason);
}
/**
* Sets the name for this auto moderation rule.
* @param {string} name The name of this auto moderation rule
* @param {string} [reason] The reason for changing the name of this auto moderation rule
* @returns {Promise<AutoModerationRule>}
*/
setName(name, reason) {
return this.edit({ name, reason });
}
/**
* Sets the event type for this auto moderation rule.
* @param {AutoModerationRuleEventType} eventType The event type of this auto moderation rule
* @param {string} [reason] The reason for changing the event type of this auto moderation rule
* @returns {Promise<AutoModerationRule>}
*/
setEventType(eventType, reason) {
return this.edit({ eventType, reason });
}
/**
* Sets the keyword filter for this auto moderation rule.
* @param {string[]} keywordFilter The keyword filter of this auto moderation rule
* @param {string} [reason] The reason for changing the keyword filter of this auto moderation rule
* @returns {Promise<AutoModerationRule>}
*/
setKeywordFilter(keywordFilter, reason) {
return this.edit({ triggerMetadata: { keywordFilter }, reason });
}
/**
* Sets the regular expression patterns for this auto moderation rule.
* @param {string[]} regexPatterns The regular expression patterns of this auto moderation rule
* <info>Only Rust-flavored regular expressions are supported.</info>
* @param {string} [reason] The reason for changing the regular expression patterns of this auto moderation rule
* @returns {Promise<AutoModerationRule>}
*/
setRegexPatterns(regexPatterns, reason) {
return this.edit({ triggerMetadata: { regexPatterns }, reason });
}
/**
* Sets the presets for this auto moderation rule.
* @param {AutoModerationRuleKeywordPresetType[]} presets The presets of this auto moderation rule
* @param {string} [reason] The reason for changing the presets of this auto moderation rule
* @returns {Promise<AutoModerationRule>}
*/
setPresets(presets, reason) {
return this.edit({ triggerMetadata: { presets }, reason });
}
/**
* Sets the allow list for this auto moderation rule.
* @param {string[]} allowList The allow list of this auto moderation rule
* @param {string} [reason] The reason for changing the allow list of this auto moderation rule
* @returns {Promise<AutoModerationRule>}
*/
setAllowList(allowList, reason) {
return this.edit({ triggerMetadata: { allowList }, reason });
}
/**
* Sets the mention total limit for this auto moderation rule.
* @param {number} mentionTotalLimit The mention total limit of this auto moderation rule
* @param {string} [reason] The reason for changing the mention total limit of this auto moderation rule
* @returns {Promise<AutoModerationRule>}
*/
setMentionTotalLimit(mentionTotalLimit, reason) {
return this.edit({ triggerMetadata: { mentionTotalLimit }, reason });
}
/**
* Sets the actions for this auto moderation rule.
* @param {AutoModerationActionOptions} actions The actions of this auto moderation rule
* @param {string} [reason] The reason for changing the actions of this auto moderation rule
* @returns {Promise<AutoModerationRule>}
*/
setActions(actions, reason) {
return this.edit({ actions, reason });
}
/**
* Sets whether this auto moderation rule should be enabled.
* @param {boolean} [enabled=true] Whether to enable this auto moderation rule
* @param {string} [reason] The reason for enabling or disabling this auto moderation rule
* @returns {Promise<AutoModerationRule>}
*/
setEnabled(enabled = true, reason) {
return this.edit({ enabled, reason });
}
/**
* Sets the exempt roles for this auto moderation rule.
* @param {Collection<Snowflake, Role>|RoleResolvable[]} [exemptRoles] The exempt roles of this auto moderation rule
* @param {string} [reason] The reason for changing the exempt roles of this auto moderation rule
* @returns {Promise<AutoModerationRule>}
*/
setExemptRoles(exemptRoles, reason) {
return this.edit({ exemptRoles, reason });
}
/**
* Sets the exempt channels for this auto moderation rule.
* @param {Collection<Snowflake, GuildChannel|ThreadChannel>|GuildChannelResolvable[]} [exemptChannels]
* The exempt channels of this auto moderation rule
* @param {string} [reason] The reason for changing the exempt channels of this auto moderation rule
* @returns {Promise<AutoModerationRule>}
*/
setExemptChannels(exemptChannels, reason) {
return this.edit({ exemptChannels, reason });
}
}
module.exports = AutoModerationRule;

View file

@ -12,6 +12,7 @@ const Integration = require('./Integration');
const Webhook = require('./Webhook');
const WelcomeScreen = require('./WelcomeScreen');
const { DiscordjsError, DiscordjsTypeError, ErrorCodes } = require('../errors');
const AutoModerationRuleManager = require('../managers/AutoModerationRuleManager');
const GuildApplicationCommandManager = require('../managers/GuildApplicationCommandManager');
const GuildBanManager = require('../managers/GuildBanManager');
const GuildChannelManager = require('../managers/GuildChannelManager');
@ -99,6 +100,12 @@ class Guild extends AnonymousGuild {
*/
this.scheduledEvents = new GuildScheduledEventManager(this);
/**
* A manager of the auto moderation rules of this guild.
* @type {AutoModerationRuleManager}
*/
this.autoModerationRules = new AutoModerationRuleManager(this);
if (!data) return;
if (data.unavailable) {
/**

View file

@ -61,6 +61,17 @@ class GuildAuditLogs {
}
}
/**
* Cached auto moderation rules.
* @type {Collection<Snowflake, AutoModerationRule>}
* @private
*/
this.autoModerationRules = data.auto_moderation_rules.reduce(
(autoModerationRules, autoModerationRule) =>
autoModerationRules.set(autoModerationRule.id, guild.autoModerationRules._add(autoModerationRule)),
new Collection(),
);
/**
* The entries for this guild's audit logs
* @type {Collection<Snowflake, GuildAuditLogsEntry>}

View file

@ -2,6 +2,7 @@
const { DiscordSnowflake } = require('@sapphire/snowflake');
const { AuditLogOptionsType, AuditLogEvent } = require('discord-api-types/v10');
const AutoModerationRule = require('./AutoModerationRule');
const { GuildScheduledEvent } = require('./GuildScheduledEvent');
const Integration = require('./Integration');
const Invite = require('./Invite');
@ -27,6 +28,7 @@ const Targets = {
Sticker: 'Sticker',
Thread: 'Thread',
ApplicationCommand: 'ApplicationCommand',
AutoModeration: 'AutoModeration',
Unknown: 'Unknown',
};
@ -46,10 +48,11 @@ const Targets = {
* * A guild scheduled event
* * A thread
* * An application command
* * An auto moderation rule
* * An object with an id key if target was deleted or fake entity
* * An object where the keys represent either the new value or the old value
* @typedef {?(Object|Guild|BaseChannel|User|Role|Invite|Webhook|GuildEmoji|Message|Integration|StageInstance|Sticker|
* GuildScheduledEvent|ApplicationCommand)} AuditLogEntryTarget
* GuildScheduledEvent|ApplicationCommand|AutoModerationRule)} AuditLogEntryTarget
*/
/**
@ -223,6 +226,15 @@ class GuildAuditLogsEntry {
};
break;
case AuditLogEvent.AutoModerationBlockMessage:
case AuditLogEvent.AutoModerationFlagToChannel:
case AuditLogEvent.AutoModerationUserCommunicationDisabled:
this.extra = {
autoModerationRuleName: data.options.auto_moderation_rule_name,
autoModerationRuleTriggerType: data.options.auto_moderation_rule_trigger_type,
};
break;
default:
break;
}
@ -352,6 +364,20 @@ class GuildAuditLogsEntry {
);
} else if (targetType === Targets.ApplicationCommand) {
this.target = logs.applicationCommands.get(data.target_id) ?? { id: data.target_id };
} else if (targetType === Targets.AutoModeration) {
this.target =
guild.autoModerationRules.cache.get(data.target_id) ??
new AutoModerationRule(
guild.client,
this.changes.reduce(
(o, c) => {
o[c.key] = c.new ?? c.old;
return o;
},
{ id: data.target_id, guild_id: guild.id },
),
guild,
);
} else if (data.target_id) {
this.target = guild[`${targetType.toLowerCase()}s`]?.cache.get(data.target_id) ?? { id: data.target_id };
}
@ -377,6 +403,7 @@ class GuildAuditLogsEntry {
if (target < 110) return Targets.GuildScheduledEvent;
if (target < 120) return Targets.Thread;
if (target < 130) return Targets.ApplicationCommand;
if (target >= 140 && target < 150) return Targets.AutoModeration;
return Targets.Unknown;
}
@ -402,6 +429,8 @@ class GuildAuditLogsEntry {
AuditLogEvent.StickerCreate,
AuditLogEvent.GuildScheduledEventCreate,
AuditLogEvent.ThreadCreate,
AuditLogEvent.AutoModerationRuleCreate,
AuditLogEvent.AutoModerationBlockMessage,
].includes(action)
) {
return 'Create';
@ -427,6 +456,7 @@ class GuildAuditLogsEntry {
AuditLogEvent.StickerDelete,
AuditLogEvent.GuildScheduledEventDelete,
AuditLogEvent.ThreadDelete,
AuditLogEvent.AutoModerationRuleDelete,
].includes(action)
) {
return 'Delete';
@ -450,6 +480,7 @@ class GuildAuditLogsEntry {
AuditLogEvent.GuildScheduledEventUpdate,
AuditLogEvent.ThreadUpdate,
AuditLogEvent.ApplicationCommandPermissionUpdate,
AuditLogEvent.AutoModerationRuleUpdate,
].includes(action)
) {
return 'Update';

View file

@ -168,6 +168,26 @@
* @see {@link https://discord-api-types.dev/api/discord-api-types-v10/enum/ApplicationFlags}
*/
/**
* @external AutoModerationActionType
* @see {@link https://discord-api-types.dev/api/discord-api-types-v10/enum/AutoModerationActionType}
*/
/**
* @external AutoModerationRuleEventType
* @see {@link https://discord-api-types.dev/api/discord-api-types-v10/enum/AutoModerationRuleEventType}
*/
/**
* @external AutoModerationRuleTriggerType
* @see {@link https://discord-api-types.dev/api/discord-api-types-v10/enum/AutoModerationRuleTriggerType}
*/
/**
* @external AutoModerationRuleKeywordPresetType
* @see {@link https://discord-api-types.dev/api/discord-api-types-v10/enum/AutoModerationRuleKeywordPresetType}
*/
/**
* @external AuditLogEvent
* @see {@link https://discord-api-types.dev/api/discord-api-types-v10/enum/AuditLogEvent}

View file

@ -10,6 +10,7 @@ exports.MaxBulkDeletableMessageAge = 1_209_600_000;
/**
* The name of an item to be swept in Sweepers
* * `autoModerationRules`
* * `applicationCommands` - both global and guild commands
* * `bans`
* * `emojis`
@ -27,6 +28,7 @@ exports.MaxBulkDeletableMessageAge = 1_209_600_000;
* @typedef {string} SweeperKey
*/
exports.SweeperKeys = [
'autoModerationRules',
'applicationCommands',
'bans',
'emojis',

View file

@ -79,6 +79,10 @@
*/
module.exports = {
ApplicationCommandPermissionsUpdate: 'applicationCommandPermissionsUpdate',
AutoModerationActionExecution: 'autoModerationActionExecution',
AutoModerationRuleCreate: 'autoModerationRuleCreate',
AutoModerationRuleDelete: 'autoModerationRuleDelete',
AutoModerationRuleUpdate: 'autoModerationRuleUpdate',
CacheSweep: 'cacheSweep',
ChannelCreate: 'channelCreate',
ChannelDelete: 'channelDelete',

View file

@ -78,6 +78,16 @@ class Sweepers {
return guildCommands + globalCommands;
}
/**
* Sweeps all auto moderation rules and removes the ones which are indicated by the filter.
* @param {Function} filter The function used to determine
* which auto moderation rules will be removed from the caches
* @returns {number} Amount of auto moderation rules that were removed from the caches
*/
sweepAutoModerationRules(filter) {
return this._sweepGuildDirectProp('autoModerationRules', filter).items;
}
/**
* Sweeps all guild bans and removes the ones which are indicated by the filter.
* @param {Function} filter The function used to determine which bans will be removed from the caches.

View file

@ -139,6 +139,13 @@ import {
APIMessageRoleSelectInteractionData,
APIMessageMentionableSelectInteractionData,
APIMessageChannelSelectInteractionData,
AutoModerationRuleKeywordPresetType,
AutoModerationActionType,
AutoModerationRuleEventType,
AutoModerationRuleTriggerType,
AuditLogRuleTriggerType,
GatewayAutoModerationActionExecutionDispatchData,
APIAutoModerationRule,
} from 'discord-api-types/v10';
import { ChildProcess } from 'node:child_process';
import { EventEmitter } from 'node:events';
@ -319,6 +326,56 @@ export abstract class AnonymousGuild extends BaseGuild {
public splashURL(options?: ImageURLOptions): string | null;
}
export class AutoModerationActionExecution {
private constructor(data: GatewayAutoModerationActionExecutionDispatchData, guild: Guild);
public guild: Guild;
public action: AutoModerationAction;
public ruleId: Snowflake;
public ruleTriggerType: AutoModerationRuleTriggerType;
public userId: Snowflake;
public channelId: Snowflake | null;
public messageId: Snowflake | null;
public alertSystemMessageId: Snowflake | null;
public content: string;
public matchedKeyword: string | null;
public matchedContent: string | null;
public get autoModerationRule(): AutoModerationRule | null;
}
export class AutoModerationRule extends Base {
private constructor(client: Client<true>, data: APIAutoModerationRule, guild: Guild);
public id: Snowflake;
public guild: Guild;
public name: string;
public creatorId: Snowflake;
public eventType: AutoModerationRuleEventType;
public triggerType: AutoModerationRuleTriggerType;
public triggerMetadata: AutoModerationTriggerMetadata;
public actions: AutoModerationAction[];
public enabled: boolean;
public exemptRoles: Collection<Snowflake, Role>;
public exemptChannels: Collection<Snowflake, GuildBasedChannel>;
public edit(options: AutoModerationRuleEditOptions): Promise<AutoModerationRule>;
public delete(reason?: string): Promise<void>;
public setName(name: string, reason?: string): Promise<AutoModerationRule>;
public setEventType(eventType: AutoModerationRuleEventType, reason?: string): Promise<AutoModerationRule>;
public setKeywordFilter(keywordFilter: string[], reason?: string): Promise<AutoModerationRule>;
public setRegexPatterns(regexPatterns: string[], reason?: string): Promise<AutoModerationRule>;
public setPresets(presets: AutoModerationRuleKeywordPresetType[], reason?: string): Promise<AutoModerationRule>;
public setAllowList(allowList: string[], reason?: string): Promise<AutoModerationRule>;
public setMentionTotalLimit(mentionTotalLimit: number, reason?: string): Promise<AutoModerationRule>;
public setActions(actions: AutoModerationActionOptions, reason?: string): Promise<AutoModerationRule>;
public setEnabled(enabled?: boolean, reason?: string): Promise<AutoModerationRule>;
public setExemptRoles(
roles: Collection<Snowflake, Role> | RoleResolvable[],
reason?: string,
): Promise<AutoModerationRule>;
public setExemptChannels(
channels: Collection<Snowflake, GuildBasedChannel> | GuildChannelResolvable[],
reason?: string,
): Promise<AutoModerationRule>;
}
export abstract class Application extends Base {
protected constructor(client: Client<true>, data: RawApplicationData);
public get createdAt(): Date;
@ -398,6 +455,8 @@ export class ApplicationFlagsBitField extends BitField<ApplicationFlagsString> {
public static resolve(bit?: BitFieldResolvable<ApplicationFlagsString, number>): number;
}
export type AutoModerationRuleResolvable = AutoModerationRule | Snowflake;
export abstract class Base {
public constructor(client: Client<true>);
public readonly client: Client<true>;
@ -1157,6 +1216,7 @@ export class Guild extends AnonymousGuild {
public maxVideoChannelUsers: number | null;
public approximateMemberCount: number | null;
public approximatePresenceCount: number | null;
public autoModerationRules: AutoModerationRuleManager;
public available: boolean;
public bans: GuildBanManager;
public channels: GuildChannelManager;
@ -1255,6 +1315,7 @@ export class GuildAuditLogs<T extends GuildAuditLogsResolvable = AuditLogEvent>
private webhooks: Collection<Snowflake, Webhook>;
private integrations: Collection<Snowflake | string, Integration>;
private guildScheduledEvents: Collection<Snowflake, GuildScheduledEvent>;
private autoModerationRules: Collection<Snowflake, AutoModerationRule>;
public entries: Collection<Snowflake, GuildAuditLogsEntry<T>>;
public toJSON(): unknown;
}
@ -2671,6 +2732,12 @@ export class Sweepers {
SweeperDefinitions['applicationCommands'][1]
>,
): number;
public sweepAutoModerationRules(
filter: CollectionSweepFilter<
SweeperDefinitions['autoModerationRules'][0],
SweeperDefinitions['autoModerationRules'][1]
>,
): number;
public sweepBans(filter: CollectionSweepFilter<SweeperDefinitions['bans'][0], SweeperDefinitions['bans'][1]>): number;
public sweepEmojis(
filter: CollectionSweepFilter<SweeperDefinitions['emojis'][0], SweeperDefinitions['emojis'][1]>,
@ -3610,6 +3677,23 @@ export class ApplicationCommandPermissionsManager<
private permissionsPath(guildId: Snowflake, commandId?: Snowflake): string;
}
export class AutoModerationRuleManager extends CachedManager<
Snowflake,
AutoModerationRule,
AutoModerationRuleResolvable
> {
private constructor(guild: Guild, iterable: unknown);
public guild: Guild;
public create(options: AutoModerationRuleCreateOptions): Promise<AutoModerationRule>;
public edit(
autoModerationRule: AutoModerationRuleResolvable,
options: AutoModerationRuleEditOptions,
): Promise<AutoModerationRule>;
public fetch(options: AutoModerationRuleResolvable | FetchAutoModerationRuleOptions): Promise<AutoModerationRule>;
public fetch(options?: FetchAutoModerationRulesOptions): Promise<Collection<Snowflake, AutoModerationRule>>;
public delete(autoModerationRule: AutoModerationRuleResolvable, reason?: string): Promise<void>;
}
export class BaseGuildEmojiManager extends CachedManager<Snowflake, GuildEmoji, EmojiResolvable> {
protected constructor(client: Client<true>, iterable?: Iterable<RawGuildEmojiData>);
public resolveIdentifier(emoji: EmojiIdentifierResolvable): string | null;
@ -4362,6 +4446,24 @@ export interface AuditLogChange {
new?: APIAuditLogChange['new_value'];
}
export interface AutoModerationAction {
type: AutoModerationActionType;
metadata: AutoModerationActionMetadata;
}
export interface AutoModerationActionMetadata {
channelId: Snowflake | null;
durationSeconds: number | null;
}
export interface AutoModerationTriggerMetadata {
keywordFilter: string[];
regexPatterns: string[];
presets: AutoModerationRuleKeywordPresetType[];
allowList: string[];
mentionTotalLimit: number | null;
}
export type AwaitMessageComponentOptions<T extends CollectedMessageInteraction> = Omit<
MessageComponentCollectorOptions<T>,
'max' | 'maxComponents' | 'maxUsers'
@ -4413,6 +4515,7 @@ export type BitFieldResolvable<T extends string, N extends number | bigint> =
export type BufferResolvable = Buffer | string;
export interface Caches {
AutoModerationRuleManager: [manager: typeof AutoModerationRuleManager, holds: typeof AutoModerationRule];
ApplicationCommandManager: [manager: typeof ApplicationCommandManager, holds: typeof ApplicationCommand];
BaseGuildEmojiManager: [manager: typeof BaseGuildEmojiManager, holds: typeof GuildEmoji];
GuildEmojiManager: [manager: typeof GuildEmojiManager, holds: typeof GuildEmoji];
@ -4505,6 +4608,13 @@ export interface WebhookCreateOptions extends ChannelWebhookCreateOptions {
export interface ClientEvents {
applicationCommandPermissionsUpdate: [data: ApplicationCommandPermissionsUpdateData];
autoModerationActionExecution: [autoModerationActionExecution: AutoModerationActionExecution];
autoModerationRuleCreate: [autoModerationRule: AutoModerationRule];
autoModerationRuleDelete: [autoModerationRule: AutoModerationRule];
autoModerationRuleUpdate: [
oldAutoModerationRule: AutoModerationRule | null,
newAutoModerationRule: AutoModerationRule,
];
cacheSweep: [message: string];
channelCreate: [channel: NonThreadGuildBasedChannel];
channelDelete: [channel: DMChannel | NonThreadGuildBasedChannel];
@ -4720,6 +4830,10 @@ export declare const Colors: {
export enum Events {
ApplicationCommandPermissionsUpdate = 'applicationCommandPermissionsUpdate',
AutoModerationActionExecution = 'autoModerationActionExecution',
AutoModerationRuleCreate = 'autoModerationRuleCreate',
AutoModerationRuleDelete = 'autoModerationRuleDelete',
AutoModerationRuleUpdate = 'autoModerationRuleUpdate',
ClientReady = 'ready',
GuildCreate = 'guildCreate',
GuildDelete = 'guildDelete',
@ -4900,6 +5014,14 @@ export interface FetchArchivedThreadOptions {
limit?: number;
}
export interface FetchAutoModerationRuleOptions extends BaseFetchOptions {
autoModerationRule: AutoModerationRuleResolvable;
}
export interface FetchAutoModerationRulesOptions {
cache?: boolean;
}
export interface FetchBanOptions extends BaseFetchOptions {
user: UserResolvable;
}
@ -5056,6 +5178,12 @@ interface GuildAuditLogsTypes {
[AuditLogEvent.ThreadUpdate]: ['Thread', 'Update'];
[AuditLogEvent.ThreadDelete]: ['Thread', 'Delete'];
[AuditLogEvent.ApplicationCommandPermissionUpdate]: ['ApplicationCommand', 'Update'];
[AuditLogEvent.AutoModerationRuleCreate]: ['AutoModerationRule', 'Create'];
[AuditLogEvent.AutoModerationRuleUpdate]: ['AutoModerationRule', 'Update'];
[AuditLogEvent.AutoModerationRuleDelete]: ['AutoModerationRule', 'Delete'];
[AuditLogEvent.AutoModerationBlockMessage]: ['AutoModerationRule', 'Create'];
[AuditLogEvent.AutoModerationFlagToChannel]: ['AutoModerationRule', 'Create'];
[AuditLogEvent.AutoModerationUserCommunicationDisabled]: ['AutoModerationRule', 'Create'];
}
export type GuildAuditLogsActionType = GuildAuditLogsTypes[keyof GuildAuditLogsTypes][1] | 'All';
@ -5087,6 +5215,18 @@ export interface GuildAuditLogsEntryExtraField {
[AuditLogEvent.StageInstanceDelete]: StageChannel | { id: Snowflake };
[AuditLogEvent.StageInstanceUpdate]: StageChannel | { id: Snowflake };
[AuditLogEvent.ApplicationCommandPermissionUpdate]: { applicationId: Snowflake };
[AuditLogEvent.AutoModerationBlockMessage]: {
autoModerationRuleName: string;
autoModerationRuleTriggerType: AuditLogRuleTriggerType;
};
[AuditLogEvent.AutoModerationFlagToChannel]: {
autoModerationRuleName: string;
autoModerationRuleTriggerType: AuditLogRuleTriggerType;
};
[AuditLogEvent.AutoModerationUserCommunicationDisabled]: {
autoModerationRuleName: string;
autoModerationRuleTriggerType: AuditLogRuleTriggerType;
};
}
export interface GuildAuditLogsEntryTargetField<TActionType extends GuildAuditLogsActionType> {
@ -5102,6 +5242,7 @@ export interface GuildAuditLogsEntryTargetField<TActionType extends GuildAuditLo
Sticker: Sticker;
GuildScheduledEvent: GuildScheduledEvent;
ApplicationCommand: ApplicationCommand;
AutoModerationRule: AutoModerationRule;
}
export interface GuildAuditLogsFetchOptions<T extends GuildAuditLogsResolvable> {
@ -5123,6 +5264,31 @@ export type GuildBanResolvable = GuildBan | UserResolvable;
export type GuildChannelResolvable = Snowflake | GuildBasedChannel;
export interface AutoModerationRuleCreateOptions {
name: string;
eventType: AutoModerationRuleEventType;
triggerType: AutoModerationRuleTriggerType;
triggerMetadata?: AutoModerationTriggerMetadataOptions;
actions: AutoModerationActionOptions;
enabled?: boolean;
exemptRoles?: Collection<Snowflake, Role> | RoleResolvable[];
exemptChannels?: Collection<Snowflake, GuildBasedChannel> | GuildChannelResolvable[];
reason?: string;
}
export interface AutoModerationRuleEditOptions extends Partial<Omit<AutoModerationRuleCreateOptions, 'triggerType'>> {}
export interface AutoModerationTriggerMetadataOptions extends Partial<AutoModerationTriggerMetadata> {}
export interface AutoModerationActionOptions {
type: AutoModerationActionType;
metadata?: AutoModerationActionMetadataOptions;
}
export interface AutoModerationActionMetadataOptions extends Partial<Omit<AutoModerationActionMetadata, 'channelId'>> {
channel: GuildTextChannelResolvable | ThreadChannel;
}
export interface GuildChannelCreateOptions extends Omit<CategoryCreateChannelOptions, 'type'> {
parent?: CategoryChannelResolvable | null;
type?: Exclude<
@ -5864,6 +6030,7 @@ export interface LifetimeSweepOptions {
export interface SweeperDefinitions {
applicationCommands: [Snowflake, ApplicationCommand];
autoModerationRules: [Snowflake, AutoModerationRule];
bans: [Snowflake, GuildBan];
emojis: [Snowflake, GuildEmoji];
invites: [string, Invite, true];

View file

@ -148,6 +148,9 @@ import {
RoleSelectMenuInteraction,
ChannelSelectMenuInteraction,
MentionableSelectMenuInteraction,
AutoModerationActionExecution,
AutoModerationRule,
AutoModerationRuleManager,
} from '.';
import { expectAssignable, expectNotAssignable, expectNotType, expectType } from 'tsd';
import type { ContextMenuCommandBuilder, SlashCommandBuilder } from '@discordjs/builders';
@ -174,8 +177,17 @@ const testUserId = '987654321098765432'; // example id
const globalCommandId = '123456789012345678'; // example id
const guildCommandId = '234567890123456789'; // example id
declare const slashCommandBuilder: SlashCommandBuilder;
declare const contextMenuCommandBuilder: ContextMenuCommandBuilder;
client.on('autoModerationActionExecution', autoModerationActionExecution =>
expectType<AutoModerationActionExecution>(autoModerationActionExecution),
);
client.on('autoModerationRuleCreate', ({ client }) => expectType<Client<true>>(client));
client.on('autoModerationRuleDelete', ({ client }) => expectType<Client<true>>(client));
client.on('autoModerationRuleUpdate', (oldAutoModerationRule, { client: newClient }) => {
expectType<Client<true>>(oldAutoModerationRule!.client);
expectType<Client<true>>(newClient);
});
client.on('channelCreate', ({ client }) => expectType<Client<true>>(client));
client.on('channelDelete', ({ client }) => expectType<Client<true>>(client));
@ -556,6 +568,9 @@ client.on('presenceUpdate', (oldPresence, { client }) => {
expectType<Client<true>>(client);
});
declare const slashCommandBuilder: SlashCommandBuilder;
declare const contextMenuCommandBuilder: ContextMenuCommandBuilder;
client.on('ready', async client => {
expectType<Client<true>>(client);
console.log(`Client is logged in as ${client.user.tag} and ready!`);
@ -1362,6 +1377,26 @@ declare const applicationSubGroupCommandData: ApplicationCommandSubGroupData;
expectType<ApplicationCommandSubCommandData[] | undefined>(applicationSubGroupCommandData.options);
}
declare const autoModerationRuleManager: AutoModerationRuleManager;
{
expectType<Promise<AutoModerationRule>>(autoModerationRuleManager.fetch('1234567890'));
expectType<Promise<AutoModerationRule>>(autoModerationRuleManager.fetch({ autoModerationRule: '1234567890' }));
expectType<Promise<AutoModerationRule>>(
autoModerationRuleManager.fetch({ autoModerationRule: '1234567890', cache: false }),
);
expectType<Promise<AutoModerationRule>>(
autoModerationRuleManager.fetch({ autoModerationRule: '1234567890', force: true }),
);
expectType<Promise<AutoModerationRule>>(
autoModerationRuleManager.fetch({ autoModerationRule: '1234567890', cache: false, force: true }),
);
expectType<Promise<Collection<Snowflake, AutoModerationRule>>>(autoModerationRuleManager.fetch());
expectType<Promise<Collection<Snowflake, AutoModerationRule>>>(autoModerationRuleManager.fetch({}));
expectType<Promise<Collection<Snowflake, AutoModerationRule>>>(autoModerationRuleManager.fetch({ cache: false }));
// @ts-expect-error The `force` option cannot be used alongside fetching all auto moderation rules.
autoModerationRuleManager.fetch({ force: false });
}
declare const guildApplicationCommandManager: GuildApplicationCommandManager;
expectType<Promise<Collection<Snowflake, ApplicationCommand>>>(guildApplicationCommandManager.fetch());
expectType<Promise<Collection<Snowflake, ApplicationCommand>>>(guildApplicationCommandManager.fetch(undefined, {}));