From 294005bac76db7d34a3991e6178076229faa35b9 Mon Sep 17 00:00:00 2001
From: March 7th <71698422+aiko-chan-ai@users.noreply.github.com>
Date: Tue, 20 Dec 2022 22:46:50 +0700
Subject: [PATCH] feat: automod
#8886 djs
---
src/client/actions/ActionsManager.js | 4 +
.../actions/AutoModerationActionExecution.js | 26 ++
.../actions/AutoModerationRuleCreate.js | 27 ++
.../actions/AutoModerationRuleDelete.js | 31 ++
.../actions/AutoModerationRuleUpdate.js | 29 ++
.../AUTO_MODERATION_ACTION_EXECUTION.js | 5 +
.../handlers/AUTO_MODERATION_RULE_CREATE.js | 5 +
.../handlers/AUTO_MODERATION_RULE_DELETE.js | 5 +
.../handlers/AUTO_MODERATION_RULE_UPDATE.js | 5 +
src/client/websocket/handlers/index.js | 4 +
src/index.js | 3 +
src/managers/AutoModerationRuleManager.js | 289 ++++++++++++++++++
.../AutoModerationActionExecution.js | 89 ++++++
src/structures/AutoModerationRule.js | 279 +++++++++++++++++
src/structures/Guild.js | 7 +
src/structures/GuildAuditLogs.js | 59 +++-
src/util/Constants.js | 55 ++++
src/util/Intents.js | 4 +
src/util/Sweepers.js | 10 +
typings/enums.d.ts | 23 ++
typings/index.d.ts | 181 ++++++++++-
typings/rawDataTypes.d.ts | 55 +++-
22 files changed, 1191 insertions(+), 4 deletions(-)
create mode 100644 src/client/actions/AutoModerationActionExecution.js
create mode 100644 src/client/actions/AutoModerationRuleCreate.js
create mode 100644 src/client/actions/AutoModerationRuleDelete.js
create mode 100644 src/client/actions/AutoModerationRuleUpdate.js
create mode 100644 src/client/websocket/handlers/AUTO_MODERATION_ACTION_EXECUTION.js
create mode 100644 src/client/websocket/handlers/AUTO_MODERATION_RULE_CREATE.js
create mode 100644 src/client/websocket/handlers/AUTO_MODERATION_RULE_DELETE.js
create mode 100644 src/client/websocket/handlers/AUTO_MODERATION_RULE_UPDATE.js
create mode 100644 src/managers/AutoModerationRuleManager.js
create mode 100644 src/structures/AutoModerationActionExecution.js
create mode 100644 src/structures/AutoModerationRule.js
diff --git a/src/client/actions/ActionsManager.js b/src/client/actions/ActionsManager.js
index 5841777..0f3f531 100644
--- a/src/client/actions/ActionsManager.js
+++ b/src/client/actions/ActionsManager.js
@@ -4,6 +4,10 @@ class ActionsManager {
constructor(client) {
this.client = client;
+ 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'));
diff --git a/src/client/actions/AutoModerationActionExecution.js b/src/client/actions/AutoModerationActionExecution.js
new file mode 100644
index 00000000..0c43801
--- /dev/null
+++ b/src/client/actions/AutoModerationActionExecution.js
@@ -0,0 +1,26 @@
+'use strict';
+
+const Action = require('./Action');
+const AutoModerationActionExecution = require('../../structures/AutoModerationActionExecution');
+const { Events } = require('../../util/Constants');
+
+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.
+ * This event requires the {@link Permissions.FLAGS.MANAGE_GUILD} permission.
+ * @event Client#autoModerationActionExecution
+ * @param {AutoModerationActionExecution} autoModerationActionExecution The data of the execution
+ */
+ client.emit(Events.AUTO_MODERATION_ACTION_EXECUTION, new AutoModerationActionExecution(data, guild));
+ }
+
+ return {};
+ }
+}
+
+module.exports = AutoModerationActionExecutionAction;
diff --git a/src/client/actions/AutoModerationRuleCreate.js b/src/client/actions/AutoModerationRuleCreate.js
new file mode 100644
index 00000000..a20bd30
--- /dev/null
+++ b/src/client/actions/AutoModerationRuleCreate.js
@@ -0,0 +1,27 @@
+'use strict';
+
+const Action = require('./Action');
+const { Events } = require('../../util/Constants');
+
+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.
+ * This event requires the {@link Permissions.FLAGS.MANAGE_GUILD} permission.
+ * @event Client#autoModerationRuleCreate
+ * @param {AutoModerationRule} autoModerationRule The created auto moderation rule
+ */
+ client.emit(Events.AUTO_MODERATION_RULE_CREATE, autoModerationRule);
+ }
+
+ return {};
+ }
+}
+
+module.exports = AutoModerationRuleCreateAction;
diff --git a/src/client/actions/AutoModerationRuleDelete.js b/src/client/actions/AutoModerationRuleDelete.js
new file mode 100644
index 00000000..a08b458
--- /dev/null
+++ b/src/client/actions/AutoModerationRuleDelete.js
@@ -0,0 +1,31 @@
+'use strict';
+
+const Action = require('./Action');
+const { Events } = require('../../util/Constants');
+
+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.
+ * This event requires the {@link Permissions.FLAGS.MANAGE_GUILD} permission.
+ * @event Client#autoModerationRuleDelete
+ * @param {AutoModerationRule} autoModerationRule The deleted auto moderation rule
+ */
+ client.emit(Events.AUTO_MODERATION_RULE_DELETE, autoModerationRule);
+ }
+ }
+
+ return {};
+ }
+}
+
+module.exports = AutoModerationRuleDeleteAction;
diff --git a/src/client/actions/AutoModerationRuleUpdate.js b/src/client/actions/AutoModerationRuleUpdate.js
new file mode 100644
index 00000000..0a608fa
--- /dev/null
+++ b/src/client/actions/AutoModerationRuleUpdate.js
@@ -0,0 +1,29 @@
+'use strict';
+
+const Action = require('./Action');
+const { Events } = require('../../util/Constants');
+
+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.
+ * This event requires the {@link Permissions.FLAGS.MANAGE_GUILD} permission.
+ * @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.AUTO_MODERATION_RULE_UPDATE, oldAutoModerationRule, newAutoModerationRule);
+ }
+
+ return {};
+ }
+}
+
+module.exports = AutoModerationRuleUpdateAction;
diff --git a/src/client/websocket/handlers/AUTO_MODERATION_ACTION_EXECUTION.js b/src/client/websocket/handlers/AUTO_MODERATION_ACTION_EXECUTION.js
new file mode 100644
index 00000000..22463b6
--- /dev/null
+++ b/src/client/websocket/handlers/AUTO_MODERATION_ACTION_EXECUTION.js
@@ -0,0 +1,5 @@
+'use strict';
+
+module.exports = (client, packet) => {
+ client.actions.AutoModerationActionExecution.handle(packet.d);
+};
diff --git a/src/client/websocket/handlers/AUTO_MODERATION_RULE_CREATE.js b/src/client/websocket/handlers/AUTO_MODERATION_RULE_CREATE.js
new file mode 100644
index 00000000..af64b9c
--- /dev/null
+++ b/src/client/websocket/handlers/AUTO_MODERATION_RULE_CREATE.js
@@ -0,0 +1,5 @@
+'use strict';
+
+module.exports = (client, packet) => {
+ client.actions.AutoModerationRuleCreate.handle(packet.d);
+};
diff --git a/src/client/websocket/handlers/AUTO_MODERATION_RULE_DELETE.js b/src/client/websocket/handlers/AUTO_MODERATION_RULE_DELETE.js
new file mode 100644
index 00000000..56ec504
--- /dev/null
+++ b/src/client/websocket/handlers/AUTO_MODERATION_RULE_DELETE.js
@@ -0,0 +1,5 @@
+'use strict';
+
+module.exports = (client, packet) => {
+ client.actions.AutoModerationRuleDelete.handle(packet.d);
+};
diff --git a/src/client/websocket/handlers/AUTO_MODERATION_RULE_UPDATE.js b/src/client/websocket/handlers/AUTO_MODERATION_RULE_UPDATE.js
new file mode 100644
index 00000000..3caf6ba
--- /dev/null
+++ b/src/client/websocket/handlers/AUTO_MODERATION_RULE_UPDATE.js
@@ -0,0 +1,5 @@
+'use strict';
+
+module.exports = (client, packet) => {
+ client.actions.AutoModerationRuleUpdate.handle(packet.d);
+};
diff --git a/src/client/websocket/handlers/index.js b/src/client/websocket/handlers/index.js
index d5d8ac5..a5f3ec8 100644
--- a/src/client/websocket/handlers/index.js
+++ b/src/client/websocket/handlers/index.js
@@ -10,6 +10,10 @@ const handlers = Object.fromEntries([
['APPLICATION_COMMAND_CREATE', require('./APPLICATION_COMMAND_CREATE')],
['APPLICATION_COMMAND_DELETE', require('./APPLICATION_COMMAND_DELETE')],
['APPLICATION_COMMAND_UPDATE', require('./APPLICATION_COMMAND_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')],
['CALL_CREATE', require('./CALL_CREATE')],
['CALL_UPDATE', require('./CALL_UPDATE')],
['CALL_DELETE', require('./CALL_DELETE')],
diff --git a/src/index.js b/src/index.js
index bb90451..c311926 100644
--- a/src/index.js
+++ b/src/index.js
@@ -38,6 +38,7 @@ exports.PurchasedFlags = require('./util/PurchasedFlags');
// 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');
@@ -76,6 +77,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.BaseCommandInteraction = require('./structures/BaseCommandInteraction');
exports.BaseGuild = require('./structures/BaseGuild');
diff --git a/src/managers/AutoModerationRuleManager.js b/src/managers/AutoModerationRuleManager.js
new file mode 100644
index 00000000..2b37326
--- /dev/null
+++ b/src/managers/AutoModerationRuleManager.js
@@ -0,0 +1,289 @@
+'use strict';
+
+const { Collection } = require('@discordjs/collection');
+const CachedManager = require('./CachedManager');
+const AutoModerationRule = require('../structures/AutoModerationRule');
+const {
+ AutoModerationRuleEventTypes,
+ AutoModerationRuleTriggerTypes,
+ AutoModerationActionTypes,
+ AutoModerationRuleKeywordPresetTypes,
+} = require('../util/Constants');
+
+/**
+ * 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
+ * Only Rust-flavored regular expressions are supported.
+ * @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.KEYWORD_PRESET}
+ * @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
+ * This property is required if using a `type` of
+ * {@link AutoModerationActionType.SEND_ALERT_MESSAGE} or {@link AutoModerationActionType.TIMEOUT}.
+ */
+
+ /**
+ * 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
+ * This property is required if using a `triggerType` of
+ * {@link AutoModerationRuleTriggerTypes.KEYWORD}, {@link AutoModerationRuleTriggerTypes.KEYWORD_PRESET},
+ * or {@link AutoModerationRuleTriggerTypes.MENTION_SPAM}.
+ * @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|RoleResolvable[]} [exemptRoles]
+ * The roles that should not be affected by the auto moderation rule
+ * @property {Collection|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}
+ */
+ async create({
+ name,
+ eventType,
+ triggerType,
+ triggerMetadata,
+ actions,
+ enabled,
+ exemptRoles,
+ exemptChannels,
+ reason,
+ }) {
+ const data = await this.client.api.guilds(this.guild.id)['auto-moderation'].rules.post({
+ data: {
+ name,
+ event_type: typeof eventType === 'number' ? eventType : AutoModerationRuleEventTypes[eventType],
+ trigger_type: typeof triggerType === 'number' ? triggerType : AutoModerationRuleTriggerTypes[triggerType],
+ trigger_metadata: triggerMetadata && {
+ keyword_filter: triggerMetadata.keywordFilter,
+ regex_patterns: triggerMetadata.regexPatterns,
+ presets: triggerMetadata.presets?.map(preset =>
+ typeof preset === 'number' ? preset : AutoModerationRuleKeywordPresetTypes[preset],
+ ),
+ allow_list: triggerMetadata.allowList,
+ mention_total_limit: triggerMetadata.mentionTotalLimit,
+ },
+ actions: actions?.map(action => ({
+ type: typeof action.type === 'number' ? action.type : AutoModerationActionTypes[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|RoleResolvable[]} [exemptRoles]
+ * The roles that should not be affected by the auto moderation rule
+ * @property {Collection|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}
+ */
+ async edit(
+ autoModerationRule,
+ { name, eventType, triggerMetadata, actions, enabled, exemptRoles, exemptChannels, reason },
+ ) {
+ const autoModerationRuleId = this.resolveId(autoModerationRule);
+
+ const data = await this.client.api
+ .guilds(this.guild.id)('auto-moderation')
+ .rules(autoModerationRuleId)
+ .patch({
+ data: {
+ name,
+ event_type: typeof eventType === 'number' ? eventType : AutoModerationRuleEventTypes[eventType],
+ trigger_metadata: triggerMetadata && {
+ keyword_filter: triggerMetadata.keywordFilter,
+ regex_patterns: triggerMetadata.regexPatterns,
+ presets: triggerMetadata.presets?.map(preset =>
+ typeof preset === 'number' ? preset : AutoModerationRuleKeywordPresetTypes[preset],
+ ),
+ allow_list: triggerMetadata.allowList,
+ mention_total_limit: triggerMetadata.mentionTotalLimit,
+ },
+ actions: actions?.map(action => ({
+ type: typeof action.type === 'number' ? action.type : AutoModerationActionTypes[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>}
+ * @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.api.guilds(this.guild.id)('auto-moderation').rules(autoModerationRule).get();
+ return this._add(data, cache);
+ }
+
+ async _fetchMany(options = {}) {
+ const data = await this.client.api.guilds(this.guild.id)('auto-moderation').rules.get();
+
+ 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}
+ */
+ async delete(autoModerationRule, reason) {
+ const autoModerationRuleId = this.resolveId(autoModerationRule);
+ await this.client.api.guilds(this.guild.id)('auto-moderation').rules(autoModerationRuleId).delete({ 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;
diff --git a/src/structures/AutoModerationActionExecution.js b/src/structures/AutoModerationActionExecution.js
new file mode 100644
index 00000000..7de7e54
--- /dev/null
+++ b/src/structures/AutoModerationActionExecution.js
@@ -0,0 +1,89 @@
+'use strict';
+
+const { AutoModerationRuleTriggerTypes } = require('../util/Constants');
+
+/**
+ * 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 = AutoModerationRuleTriggerTypes[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}
+ * This will not be present if the message was blocked or the content was not part of any message.
+ */
+ 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.
+ * This property requires the {@link GatewayIntentBits.MessageContent} privileged gateway intent.
+ * @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;
diff --git a/src/structures/AutoModerationRule.js b/src/structures/AutoModerationRule.js
new file mode 100644
index 00000000..1d88259
--- /dev/null
+++ b/src/structures/AutoModerationRule.js
@@ -0,0 +1,279 @@
+'use strict';
+
+const { Collection } = require('@discordjs/collection');
+const Base = require('./Base');
+const {
+ AutoModerationRuleKeywordPresetTypes,
+ AutoModerationRuleTriggerTypes,
+ AutoModerationRuleEventTypes,
+ AutoModerationActionTypes,
+} = require('../util/Constants');
+
+/**
+ * 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 = AutoModerationRuleTriggerTypes[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 = AutoModerationRuleEventTypes[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
+ * Only Rust-flavored regular expressions are supported.
+ * @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 AutoModerationRuleTriggerTypes.Keyword} and {@link AutoModerationRuleTriggerTypes.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?.map(preset => AutoModerationRuleKeywordPresetTypes[preset]) ?? [],
+ 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: AutoModerationActionTypes[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}
+ */
+ 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}
+ */
+ 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}
+ */
+ 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}
+ */
+ 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}
+ */
+ 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}
+ */
+ 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}
+ */
+ setKeywordFilter(keywordFilter, reason) {
+ return this.edit({ triggerMetadata: { ...this.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
+ * Only Rust-flavored regular expressions are supported.
+ * @param {string} [reason] The reason for changing the regular expression patterns of this auto moderation rule
+ * @returns {Promise}
+ */
+ setRegexPatterns(regexPatterns, reason) {
+ return this.edit({ triggerMetadata: { ...this.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}
+ */
+ setPresets(presets, reason) {
+ return this.edit({ triggerMetadata: { ...this.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}
+ */
+ setAllowList(allowList, reason) {
+ return this.edit({ triggerMetadata: { ...this.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}
+ */
+ setMentionTotalLimit(mentionTotalLimit, reason) {
+ return this.edit({ triggerMetadata: { ...this.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}
+ */
+ 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}
+ */
+ setEnabled(enabled = true, reason) {
+ return this.edit({ enabled, reason });
+ }
+
+ /**
+ * Sets the exempt roles for this auto moderation rule.
+ * @param {Collection|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}
+ */
+ setExemptRoles(exemptRoles, reason) {
+ return this.edit({ exemptRoles, reason });
+ }
+
+ /**
+ * Sets the exempt channels for this auto moderation rule.
+ * @param {Collection|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}
+ */
+ setExemptChannels(exemptChannels, reason) {
+ return this.edit({ exemptChannels, reason });
+ }
+}
+
+module.exports = AutoModerationRule;
diff --git a/src/structures/Guild.js b/src/structures/Guild.js
index f1f765a..1ca23b4 100644
--- a/src/structures/Guild.js
+++ b/src/structures/Guild.js
@@ -10,6 +10,7 @@ const Integration = require('./Integration');
const Webhook = require('./Webhook');
const WelcomeScreen = require('./WelcomeScreen');
const { Error } = require('../errors');
+const AutoModerationRuleManager = require('../managers/AutoModerationRuleManager');
const GuildBanManager = require('../managers/GuildBanManager');
const GuildChannelManager = require('../managers/GuildChannelManager');
const GuildEmojiManager = require('../managers/GuildEmojiManager');
@@ -111,6 +112,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) {
diff --git a/src/structures/GuildAuditLogs.js b/src/structures/GuildAuditLogs.js
index 48086c3..6626764 100644
--- a/src/structures/GuildAuditLogs.js
+++ b/src/structures/GuildAuditLogs.js
@@ -1,13 +1,14 @@
'use strict';
const { Collection } = require('@discordjs/collection');
+const AutoModerationRule = require('./AutoModerationRule');
const { GuildScheduledEvent } = require('./GuildScheduledEvent');
const Integration = require('./Integration');
const Invite = require('./Invite');
const { StageInstance } = require('./StageInstance');
const { Sticker } = require('./Sticker');
const Webhook = require('./Webhook');
-const { OverwriteTypes, PartialTypes } = require('../util/Constants');
+const { OverwriteTypes, PartialTypes, AutoModerationRuleTriggerTypes } = require('../util/Constants');
const SnowflakeUtil = require('../util/SnowflakeUtil');
const Util = require('../util/Util');
@@ -26,6 +27,7 @@ const Util = require('../util/Util');
* * STICKER
* * THREAD
* * GUILD_SCHEDULED_EVENT
+ * * AUTO_MODERATION
* @typedef {string} AuditLogTargetType
*/
@@ -49,6 +51,7 @@ const Targets = {
STAGE_INSTANCE: 'STAGE_INSTANCE',
STICKER: 'STICKER',
THREAD: 'THREAD',
+ AUTO_MODERATION: 'AUTO_MODERATION',
UNKNOWN: 'UNKNOWN',
};
@@ -102,6 +105,12 @@ const Targets = {
* * THREAD_CREATE: 110
* * THREAD_UPDATE: 111
* * THREAD_DELETE: 112
+ * * AUTO_MODERATION_RULE_CREATE: 140
+ * * AUTO_MODERATION_RULE_UPDATE: 141
+ * * AUTO_MODERATION_RULE_DELETE: 142
+ * * AUTO_MODERATION_BLOCK_MESSAGE: 143
+ * * AUTO_MODERATION_FLAG_TO_CHANNEL: 144
+ * * AUTO_MODERATION_USER_COMMUNICATION_DISABLED: 145
* @typedef {?(number|string)} AuditLogAction
* @see {@link https://discord.com/developers/docs/resources/audit-log#audit-log-entry-object-audit-log-events}
*/
@@ -160,6 +169,12 @@ const Actions = {
THREAD_CREATE: 110,
THREAD_UPDATE: 111,
THREAD_DELETE: 112,
+ AUTO_MODERATION_RULE_CREATE: 140,
+ AUTO_MODERATION_RULE_UPDATE: 141,
+ AUTO_MODERATION_RULE_DELETE: 142,
+ AUTO_MODERATION_BLOCK_MESSAGE: 143,
+ AUTO_MODERATION_FLAG_TO_CHANNEL: 144,
+ AUTO_MODERATION_USER_COMMUNICATION_DISABLED: 145,
};
/**
@@ -193,6 +208,17 @@ class GuildAuditLogs {
}
}
+ /**
+ * Cached auto moderation rules.
+ * @type {Collection}
+ * @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}
@@ -229,10 +255,11 @@ class GuildAuditLogs {
* * A sticker
* * A guild scheduled event
* * A thread
+ * * An auto moderation rule
* * An object with an id key if target was deleted
* * An object where the keys represent either the new value or the old value
* @typedef {?(Object|Guild|Channel|User|Role|Invite|Webhook|GuildEmoji|Message|Integration|StageInstance|Sticker|
- * GuildScheduledEvent)} AuditLogEntryTarget
+ * GuildScheduledEvent|AutoModerationRule)} AuditLogEntryTarget
*/
/**
@@ -254,6 +281,7 @@ class GuildAuditLogs {
if (target < 100) return Targets.STICKER;
if (target < 110) return Targets.GUILD_SCHEDULED_EVENT;
if (target < 120) return Targets.THREAD;
+ if (target >= 140 && target < 150) return Targets.AUTO_MODERATION;
return Targets.UNKNOWN;
}
@@ -288,6 +316,8 @@ class GuildAuditLogs {
Actions.STICKER_CREATE,
Actions.GUILD_SCHEDULED_EVENT_CREATE,
Actions.THREAD_CREATE,
+ Actions.AUTO_MODERATION_RULE_CREATE,
+ Actions.AUTO_MODERATION_BLOCK_MESSAGE,
].includes(action)
) {
return 'CREATE';
@@ -313,6 +343,7 @@ class GuildAuditLogs {
Actions.STICKER_DELETE,
Actions.GUILD_SCHEDULED_EVENT_DELETE,
Actions.THREAD_DELETE,
+ Actions.AUTO_MODERATION_RULE_DELETE,
].includes(action)
) {
return 'DELETE';
@@ -335,6 +366,7 @@ class GuildAuditLogs {
Actions.STICKER_UPDATE,
Actions.GUILD_SCHEDULED_EVENT_UPDATE,
Actions.THREAD_UPDATE,
+ Actions.AUTO_MODERATION_RULE_UPDATE,
].includes(action)
) {
return 'UPDATE';
@@ -476,6 +508,15 @@ class GuildAuditLogsEntry {
};
break;
+ case Actions.AUTO_MODERATION_BLOCK_MESSAGE:
+ case Actions.AUTO_MODERATION_FLAG_TO_CHANNEL:
+ case Actions.AUTO_MODERATION_USER_COMMUNICATION_DISABLED:
+ this.extra = {
+ autoModerationRuleName: data.options.auto_moderation_rule_name,
+ autoModerationRuleTriggerType: AutoModerationRuleTriggerTypes[data.options.auto_moderation_rule_trigger_type],
+ };
+ break;
+
default:
break;
}
@@ -603,6 +644,20 @@ class GuildAuditLogsEntry {
{ id: data.target_id, guild_id: guild.id },
),
);
+ } else if (targetType === Targets.AUTO_MODERATION) {
+ 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 };
}
diff --git a/src/util/Constants.js b/src/util/Constants.js
index b1f2ed1..5a6c728 100644
--- a/src/util/Constants.js
+++ b/src/util/Constants.js
@@ -329,6 +329,10 @@ exports.Opcodes = {
* * APPLICATION_COMMAND_CREATE: applicationCommandCreate (deprecated)
* * APPLICATION_COMMAND_DELETE: applicationCommandDelete (deprecated)
* * APPLICATION_COMMAND_UPDATE: applicationCommandUpdate (deprecated)
+ * * AUTO_MODERATION_ACTION_EXECUTION: autoModerationActionExecution
+ * * AUTO_MODERATION_RULE_CREATE: autoModerationRuleCreate
+ * * AUTO_MODERATION_RULE_DELETE: autoModerationRuleDelete
+ * * AUTO_MODERATION_RULE_UPDATE: autoModerationRuleUpdate
* * CALL_CREATE: callCreate
* * CALL_DELETE: callDelete
* * CALL_UPDATE: callUpdate
@@ -414,6 +418,10 @@ exports.Events = {
APPLICATION_COMMAND_CREATE: 'applicationCommandCreate',
APPLICATION_COMMAND_DELETE: 'applicationCommandDelete',
APPLICATION_COMMAND_UPDATE: 'applicationCommandUpdate',
+ AUTO_MODERATION_ACTION_EXECUTION: 'autoModerationActionExecution',
+ AUTO_MODERATION_RULE_CREATE: 'autoModerationRuleCreate',
+ AUTO_MODERATION_RULE_DELETE: 'autoModerationRuleDelete',
+ AUTO_MODERATION_RULE_UPDATE: 'autoModerationRuleUpdate',
CALL_CREATE: 'callCreate',
CALL_DELETE: 'callDelete',
CALL_UPDATE: 'callUpdate',
@@ -753,6 +761,7 @@ exports.MessageTypes = [
/**
* The name of an item to be swept in Sweepers
* * `applicationCommands` - both global and guild commands
+ * * `autoModerationRules`
* * `bans`
* * `emojis`
* * `invites` - accepts the `lifetime` property, using it will sweep based on expires timestamp
@@ -770,6 +779,7 @@ exports.MessageTypes = [
*/
exports.SweeperKeys = [
'applicationCommands',
+ 'autoModerationRules',
'bans',
'emojis',
'invites',
@@ -1462,6 +1472,46 @@ exports.ApplicationCommandOptionTypes = createEnum([
*/
exports.ApplicationCommandPermissionTypes = createEnum([null, 'ROLE', 'USER']);
+/**
+ * The type of an {@link AutoModerationRuleTriggerTypes} object:
+ * * KEYWORD
+ * * SPAM
+ * * KEYWORD_PRESET
+ * * MENTION_SPAM
+ * @typedef {string} AutoModerationRuleTriggerType
+ * @see {@link https://discord.com/developers/docs/resources/auto-moderation#auto-moderation-rule-object-trigger-types}
+ */
+exports.AutoModerationRuleTriggerTypes = createEnum([null, 'KEYWORD', null, 'SPAM', 'KEYWORD_PRESET', 'MENTION_SPAM']);
+
+/**
+ * The type of an {@link AutoModerationRuleKeywordPresetTypes} object:
+ * * KEYWORD
+ * * SPAM
+ * * KEYWORD_PRESET
+ * * MENTION_SPAM
+ * @typedef {string} AutoModerationRuleKeywordPresetType
+ * @see {@link https://discord.com/developers/docs/resources/auto-moderation#auto-moderation-rule-object-keyword-preset-types}
+ */
+exports.AutoModerationRuleKeywordPresetTypes = createEnum([null, 'PROFANITY', 'SEXUAL_CONTENT', 'SLURS']);
+/**
+ * The type of an {@link AutoModerationActionTypes} object:
+ * * BLOCK_MESSAGE
+ * * SEND_ALERT_MESSAGE
+ * * TIMEOUT
+ * @typedef {string} AutoModerationActionType
+ * @see {@link https://discord.com/developers/docs/resources/auto-moderation#auto-moderation-action-object-action-types}
+ */
+exports.AutoModerationActionTypes = createEnum([null, 'BLOCK_MESSAGE', 'SEND_ALERT_MESSAGE', 'TIMEOUT']);
+
+/**
+ * The type of an {@link AutoModerationRuleEventTypes} object:
+ * * MESSAGE_SEND
+ * @typedef {string} AutoModerationRuleEventType
+ * @see {@link https://discord.com/developers/docs/resources/auto-moderation#auto-moderation-rule-object-event-types}
+ */
+
+exports.AutoModerationRuleEventTypes = createEnum([null, 'MESSAGE_SEND']);
+
/**
* The type of an {@link Interaction} object:
* * PING
@@ -1709,6 +1759,11 @@ function createEnum(keys) {
* The type of an {@link ApplicationCommandPermissions} object.
* @property {Object} ApplicationCommandTypes
* The type of an {@link ApplicationCommand} object.
+ * @property {Object} AutoModerationRuleTriggerTypes Characterizes the type
+ * of contentwhich can trigger the rule.
+ * @property {Object} AutoModerationActionTypes
+ * @property {Object} AutoModerationRuleKeywordPresetTypes
+ * @property {Object} AutoModerationRuleEventTypes
* @property {Object} ChannelTypes All available channel types.
* @property {ClientApplicationAssetTypes} ClientApplicationAssetTypes The types of an {@link ApplicationAsset} object.
* @property {Object} Colors An object with regularly used colors.
diff --git a/src/util/Intents.js b/src/util/Intents.js
index 6600f59..77f856e 100644
--- a/src/util/Intents.js
+++ b/src/util/Intents.js
@@ -42,6 +42,8 @@ class Intents extends BitField {}
* * `DIRECT_MESSAGE_TYPING`
* * `MESSAGE_CONTENT`
* * `GUILD_SCHEDULED_EVENTS`
+ * * `AUTO_MODERATION_CONFIGURATION`
+ * * `AUTO_MODERATION_EXECUTION`
* @type {Object}
* @see {@link https://discord.com/developers/docs/topics/gateway#list-of-intents}
*/
@@ -63,6 +65,8 @@ Intents.FLAGS = {
DIRECT_MESSAGE_TYPING: 1 << 14,
MESSAGE_CONTENT: 1 << 15,
GUILD_SCHEDULED_EVENTS: 1 << 16,
+ AUTO_MODERATION_CONFIGURATION: 1 << 20,
+ AUTO_MODERATION_EXECUTION: 1 << 21,
};
module.exports = Intents;
diff --git a/src/util/Sweepers.js b/src/util/Sweepers.js
index a826115..a104d3f 100644
--- a/src/util/Sweepers.js
+++ b/src/util/Sweepers.js
@@ -77,6 +77,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.
diff --git a/typings/enums.d.ts b/typings/enums.d.ts
index d800df5..f2e96bb 100644
--- a/typings/enums.d.ts
+++ b/typings/enums.d.ts
@@ -96,6 +96,29 @@ export const enum ApplicationCommandPermissionTypes {
USER = 2,
}
+export const enum AutoModerationRuleTriggerTypes {
+ KEYWORD = 1,
+ SPAM = 2,
+ KEYWORD_PRESET = 3,
+ MENTION_SPAM = 4,
+}
+
+export const enum AutoModerationRuleKeywordPresetTypes {
+ PROFANITY = 1,
+ SEXUAL_CONTENT = 2,
+ SLURS = 3,
+}
+
+export const enum AutoModerationActionTypes {
+ BLOCK_MESSAGE = 1,
+ SEND_ALERT_MESSAGE = 2,
+ TIMEOUT = 3,
+}
+
+export const enum AutoModerationRuleEventTypes {
+ MESSAGE_SEND = 1,
+}
+
export const enum ChannelTypes {
GUILD_TEXT = 0,
DM = 1,
diff --git a/typings/index.d.ts b/typings/index.d.ts
index a7254dc..062e1bb 100644
--- a/typings/index.d.ts
+++ b/typings/index.d.ts
@@ -66,6 +66,10 @@ import {
ApplicationCommandOptionTypes,
ApplicationCommandPermissionTypes,
ApplicationCommandTypes,
+ AutoModerationActionTypes,
+ AutoModerationRuleEventTypes,
+ AutoModerationRuleKeywordPresetTypes,
+ AutoModerationRuleTriggerTypes,
ChannelTypes,
RelationshipTypes,
localeSetting,
@@ -103,6 +107,8 @@ import {
SelectMenuComponentTypes,
} from './enums';
import {
+ APIAutoModerationRule,
+ GatewayAutoModerationActionExecutionDispatchData,
RawActivityData,
RawAnonymousGuildData,
RawApplicationCommandData,
@@ -523,6 +529,8 @@ export class ApplicationCommand extends Base {
export type ApplicationResolvable = Application | Activity | Snowflake;
+export type AutoModerationRuleResolvable = AutoModerationRule | Snowflake;
+
export class ApplicationFlags extends BitField {
public static FLAGS: Record;
public static resolve(bit?: BitFieldResolvable): number;
@@ -1259,6 +1267,7 @@ export class Guild extends AnonymousGuild {
public applicationId: Snowflake | null;
public approximateMemberCount: number | null;
public approximatePresenceCount: number | null;
+ public autoModerationRules: AutoModerationRuleManager;
public available: boolean;
public bans: GuildBanManager;
public channels: GuildChannelManager;
@@ -1372,6 +1381,7 @@ export class GuildAuditLogs {
private constructor(guild: Guild, data: RawGuildAuditLogData);
private webhooks: Collection;
private integrations: Collection;
+ private autoModerationRules: Collection;
public entries: Collection>;
@@ -3507,6 +3517,10 @@ export const Constants: {
DefaultMessageNotificationLevels: EnumHolder;
VerificationLevels: EnumHolder;
MembershipStates: EnumHolder;
+ AutoModerationRuleTriggerTypes: EnumHolder;
+ AutoModerationRuleKeywordPresetTypes: EnumHolder;
+ AutoModerationActionTypes: EnumHolder;
+ AutoModerationRuleEventTypes: EnumHolder;
ApplicationCommandOptionTypes: EnumHolder;
ApplicationCommandPermissionTypes: EnumHolder;
InteractionTypes: EnumHolder;
@@ -4440,6 +4454,13 @@ export interface ClientEvents extends BaseClientEvents {
applicationCommandDelete: [command: ApplicationCommand];
/** @deprecated See [this issue](https://github.com/discord/discord-api-docs/issues/3690) for more information. */
applicationCommandUpdate: [oldCommand: ApplicationCommand | null, newCommand: ApplicationCommand];
+ 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];
@@ -4935,6 +4956,84 @@ export type ApplicationCommandType = keyof typeof ApplicationCommandTypes;
export type ApplicationCommandOptionType = keyof typeof ApplicationCommandOptionTypes;
+export type AutoModerationRuleTriggerType = keyof typeof AutoModerationRuleTriggerTypes;
+
+export type AutoModerationRuleKeywordPresetType = keyof typeof AutoModerationRuleKeywordPresetTypes;
+
+export type AutoModerationActionType = keyof typeof AutoModerationActionTypes;
+
+export type AutoModerationRuleEventType = keyof typeof AutoModerationRuleEventTypes;
+
+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, 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;
+ public exemptChannels: Collection;
+ public edit(options: AutoModerationRuleEditOptions): Promise;
+ public delete(reason?: string): Promise;
+ public setName(name: string, reason?: string): Promise;
+ public setEventType(
+ eventType: AutoModerationRuleEventType | AutoModerationRuleEventTypes,
+ reason?: string,
+ ): Promise;
+ public setKeywordFilter(keywordFilter: string[], reason?: string): Promise;
+ public setRegexPatterns(regexPatterns: string[], reason?: string): Promise;
+ public setPresets(presets: AutoModerationRuleKeywordPresetType[], reason?: string): Promise;
+ public setAllowList(allowList: string[], reason?: string): Promise;
+ public setMentionTotalLimit(mentionTotalLimit: number, reason?: string): Promise;
+ public setActions(actions: AutoModerationActionOptions, reason?: string): Promise;
+ public setEnabled(enabled?: boolean, reason?: string): Promise;
+ public setExemptRoles(
+ roles: Collection | RoleResolvable[],
+ reason?: string,
+ ): Promise;
+ public setExemptChannels(
+ channels: Collection | GuildChannelResolvable[],
+ reason?: string,
+ ): Promise;
+}
+
+export class AutoModerationRuleManager extends CachedManager<
+ Snowflake,
+ AutoModerationRule,
+ AutoModerationRuleResolvable
+> {
+ private constructor(guild: Guild, iterable: unknown);
+ public guild: Guild;
+ public create(options: AutoModerationRuleCreateOptions): Promise;
+ public edit(
+ autoModerationRule: AutoModerationRuleResolvable,
+ options: AutoModerationRuleEditOptions,
+ ): Promise;
+ public fetch(options: AutoModerationRuleResolvable | FetchAutoModerationRuleOptions): Promise;
+ public fetch(options?: FetchAutoModerationRulesOptions): Promise>;
+ public delete(autoModerationRule: AutoModerationRuleResolvable, reason?: string): Promise;
+}
+
export interface ApplicationCommandPermissionData {
id: Snowflake;
type: ApplicationCommandPermissionType | ApplicationCommandPermissionTypes;
@@ -4961,6 +5060,57 @@ export type ApplicationFlagsString =
| 'EMBEDDED_FIRST_PARTY'
| 'APPLICATION_COMMAND_BADGE';
+export interface AutoModerationAction {
+ type: AutoModerationActionType | AutoModerationActionTypes;
+ metadata: AutoModerationActionMetadata;
+}
+
+export interface AutoModerationActionMetadata {
+ channelId: Snowflake | null;
+ durationSeconds: number | null;
+}
+
+export interface AutoModerationTriggerMetadata {
+ keywordFilter: string[];
+ regexPatterns: string[];
+ presets: (AutoModerationRuleKeywordPresetType | AutoModerationRuleKeywordPresetTypes)[];
+ allowList: string[];
+ mentionTotalLimit: number | null;
+}
+
+export interface FetchAutoModerationRuleOptions extends BaseFetchOptions {
+ autoModerationRule: AutoModerationRuleResolvable;
+}
+
+export interface FetchAutoModerationRulesOptions {
+ cache?: boolean;
+}
+
+export interface AutoModerationRuleCreateOptions {
+ name: string;
+ eventType: AutoModerationRuleEventType | AutoModerationRuleEventTypes;
+ triggerType: AutoModerationRuleTriggerType | AutoModerationRuleTriggerTypes;
+ triggerMetadata?: AutoModerationTriggerMetadataOptions;
+ actions: AutoModerationActionOptions;
+ enabled?: boolean;
+ exemptRoles?: Collection | RoleResolvable[];
+ exemptChannels?: Collection | GuildChannelResolvable[];
+ reason?: string;
+}
+
+export interface AutoModerationRuleEditOptions extends Partial> {}
+
+export interface AutoModerationTriggerMetadataOptions extends Partial {}
+
+export interface AutoModerationActionOptions {
+ type: AutoModerationActionType | AutoModerationActionTypes;
+ metadata?: AutoModerationActionMetadataOptions;
+}
+
+export interface AutoModerationActionMetadataOptions extends Partial> {
+ channel: GuildTextChannelResolvable | ThreadChannel;
+}
+
export interface AuditLogChange {
key: APIAuditLogChange['key'];
old?: APIAuditLogChange['old_value'];
@@ -5020,6 +5170,7 @@ export type BufferResolvable = Buffer | string;
export interface Caches {
ApplicationCommandManager: [manager: typeof ApplicationCommandManager, holds: typeof ApplicationCommand];
+ AutoModerationRuleManager: [manager: typeof AutoModerationRuleManager, holds: typeof AutoModerationRule];
BaseGuildEmojiManager: [manager: typeof BaseGuildEmojiManager, holds: typeof GuildEmoji];
GuildEmojiManager: [manager: typeof GuildEmojiManager, holds: typeof GuildEmoji];
// TODO: ChannelManager: [manager: typeof ChannelManager, holds: typeof Channel];
@@ -5579,6 +5730,12 @@ interface GuildAuditLogsTypes {
THREAD_CREATE: ['THREAD', 'CREATE'];
THREAD_UPDATE: ['THREAD', 'UPDATE'];
THREAD_DELETE: ['THREAD', 'DELETE'];
+ AUTO_MODERATION_RULE_CREATE: ['AUTO_MODERATION', 'CREATE'];
+ AUTO_MODERATION_RULE_UPDATE: ['AUTO_MODERATION', 'UPDATE'];
+ AUTO_MODERATION_RULE_DELETE: ['AUTO_MODERATION', 'DELETE'];
+ AUTO_MODERATION_BLOCK_MESSAGE: ['AUTO_MODERATION', 'CREATE'];
+ AUTO_MODERATION_FLAG_TO_CHANNEL: ['AUTO_MODERATION', 'CREATE'];
+ AUTO_MODERATION_USER_COMMUNICATION_DISABLED: ['AUTO_MODERATION', 'CREATE'];
}
export interface GuildAuditLogsIds {
@@ -5629,6 +5786,12 @@ export interface GuildAuditLogsIds {
110: 'THREAD_CREATE';
111: 'THREAD_UPDATE';
112: 'THREAD_DELETE';
+ 140: 'AUTO_MODERATION_RULE_CREATE';
+ 141: 'AUTO_MODERATION_RULE_UPDATE';
+ 142: 'AUTO_MODERATION_RULE_DELETE';
+ 143: 'AUTO_MODERATION_BLOCK_MESSAGE';
+ 144: 'AUTO_MODERATION_FLAG_TO_CHANNEL';
+ 145: 'AUTO_MODERATION_USER_COMMUNICATION_DISABLED';
}
export type GuildAuditLogsActions = { [Key in keyof GuildAuditLogsIds as GuildAuditLogsIds[Key]]: Key } & { ALL: null };
@@ -5663,6 +5826,18 @@ export interface GuildAuditLogsEntryExtraField {
STAGE_INSTANCE_CREATE: StageChannel | { id: Snowflake };
STAGE_INSTANCE_DELETE: StageChannel | { id: Snowflake };
STAGE_INSTANCE_UPDATE: StageChannel | { id: Snowflake };
+ AUTO_MODERATION_BLOCK_MESSAGE: {
+ autoModerationRuleName: string;
+ autoModerationRuleTriggerType: AutoModerationRuleTriggerType;
+ };
+ AUTO_MODERATION_FLAG_TO_CHANNEL: {
+ autoModerationRuleName: string;
+ autoModerationRuleTriggerType: AutoModerationRuleTriggerType;
+ };
+ AUTO_MODERATION_USER_COMMUNICATIONDISABLED: {
+ autoModerationRuleName: string;
+ autoModerationRuleTriggerType: AutoModerationRuleTriggerType;
+ };
}
export interface GuildAuditLogsEntryTargetField {
@@ -5677,6 +5852,7 @@ export interface GuildAuditLogsEntryTargetField {
@@ -5994,7 +6170,9 @@ export type IntentsString =
| 'DIRECT_MESSAGE_REACTIONS'
| 'DIRECT_MESSAGE_TYPING'
| 'MESSAGE_CONTENT'
- | 'GUILD_SCHEDULED_EVENTS';
+ | 'GUILD_SCHEDULED_EVENTS'
+ | 'AUTO_MODERATION_CONFIGURATION'
+ | 'AUTO_MODERATION_EXECUTION';
export interface InviteGenerationOptions {
permissions?: PermissionResolvable;
@@ -6703,6 +6881,7 @@ export interface LifetimeSweepOptions {
export interface SweeperDefinitions {
applicationCommands: [Snowflake, ApplicationCommand];
+ autoModerationRules: [Snowflake, AutoModerationRule];
bans: [Snowflake, GuildBan];
emojis: [Snowflake, GuildEmoji];
invites: [string, Invite, true];
diff --git a/typings/rawDataTypes.d.ts b/typings/rawDataTypes.d.ts
index 7c69081..b292755 100644
--- a/typings/rawDataTypes.d.ts
+++ b/typings/rawDataTypes.d.ts
@@ -82,7 +82,15 @@ import {
APIModalSubmitInteraction,
} from 'discord-api-types/v9';
import { GuildChannel, Guild, PermissionOverwrites, InteractionType } from '.';
-import type { InteractionTypes, MessageComponentTypes } from './enums';
+
+import type {
+ AutoModerationActionTypes,
+ AutoModerationRuleEventTypes,
+ AutoModerationRuleKeywordPresetTypes,
+ AutoModerationRuleTriggerTypes,
+ InteractionTypes,
+ MessageComponentTypes,
+} from './enums';
export type RawActivityData = GatewayActivity;
@@ -216,3 +224,48 @@ export type RawWelcomeScreenData = APIGuildWelcomeScreen;
export type RawWidgetData = APIGuildWidget;
export type RawWidgetMemberData = APIGuildWidgetMember;
+
+export interface GatewayAutoModerationActionExecutionDispatchData {
+ guild_id: Snowflake;
+ action: APIAutoModerationAction;
+ rule_id: Snowflake;
+ rule_trigger_type: AutoModerationRuleTriggerTypes;
+ user_id: Snowflake;
+ channel_id?: Snowflake;
+ message_id?: Snowflake;
+ alert_system_message_id?: Snowflake;
+ content: string;
+ matched_keyword: string | null;
+ matched_content: string | null;
+}
+
+export interface APIAutoModerationAction {
+ type: AutoModerationActionTypes;
+ metadata?: APIAutoModerationActionMetadata;
+}
+export interface APIAutoModerationActionMetadata {
+ channel_id?: Snowflake;
+ duration_seconds?: number;
+}
+
+export interface APIAutoModerationRule {
+ id: Snowflake;
+ guild_id: Snowflake;
+ name: string;
+ creator_id: Snowflake;
+ event_type: AutoModerationRuleEventTypes;
+ trigger_type: AutoModerationRuleTriggerTypes;
+ trigger_metadata: APIAutoModerationRuleTriggerMetadata;
+ actions: APIAutoModerationAction[];
+ enabled: boolean;
+ exempt_roles: Snowflake[];
+ exempt_channels: Snowflake[];
+}
+
+export interface APIAutoModerationRuleTriggerMetadata {
+ keyword_filter?: string[];
+ presets?: AutoModerationRuleKeywordPresetTypes[];
+ allow_list?: string[];
+ regex_patterns?: string[];
+ mention_total_limit?: number;
+}
\ No newline at end of file