aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--.eslintrc.json22
-rw-r--r--package.json26
-rw-r--r--src/arguments/discordEmoji.ts4
-rw-r--r--src/commands/config/config.ts1
-rw-r--r--src/commands/config/features.ts2
-rw-r--r--src/commands/dev/servers.ts4
-rw-r--r--src/commands/dev/test.ts10
-rw-r--r--src/commands/info/guildInfo.ts2
-rw-r--r--src/commands/info/help.ts3
-rw-r--r--src/commands/info/links.ts3
-rw-r--r--src/commands/info/userInfo.ts2
-rw-r--r--src/commands/moulberry-bush/capes.ts2
-rw-r--r--src/commands/utilities/highlight-!.ts2
-rw-r--r--src/commands/utilities/reminders.ts2
-rw-r--r--src/lib/common/AutoMod.ts2
-rw-r--r--src/lib/common/ButtonPaginator.ts7
-rw-r--r--src/lib/common/ConfirmationPrompt.ts2
-rw-r--r--src/lib/common/DeleteButton.ts1
-rw-r--r--src/lib/common/util/Moderation.ts124
-rw-r--r--src/lib/extensions/discord-akairo/BushClientUtil.ts2
-rw-r--r--src/lib/extensions/discord-akairo/BushCommand.ts6
-rw-r--r--src/lib/extensions/discord.js/BushGuild.ts29
-rw-r--r--src/lib/extensions/discord.js/BushGuildMember.ts127
-rw-r--r--src/lib/models/instance/Guild.ts9
-rw-r--r--src/lib/utils/BushConstants.ts4
-rw-r--r--src/listeners/client/interactionCreate.ts2
-rw-r--r--src/listeners/track-manual-punishments/modlogSyncBan.ts2
-rw-r--r--src/listeners/track-manual-punishments/modlogSyncKick.ts2
-rw-r--r--src/listeners/track-manual-punishments/modlogSyncTimeout.ts2
-rw-r--r--src/listeners/track-manual-punishments/modlogSyncUnban.ts2
-rw-r--r--src/listeners/ws/INTERACTION_CREATE.ts246
-rw-r--r--yarn.lock337
32 files changed, 694 insertions, 297 deletions
diff --git a/.eslintrc.json b/.eslintrc.json
index 1d9ffcf..5209b65 100644
--- a/.eslintrc.json
+++ b/.eslintrc.json
@@ -10,7 +10,7 @@
"sourceType": "module",
"project": "./tsconfig.json"
},
- "plugins": ["@typescript-eslint", "deprecation", "node", "import"],
+ "plugins": ["@typescript-eslint", "deprecation", "import"],
"ignorePatterns": ["dist"],
"rules": {
"no-return-await": "off",
@@ -61,8 +61,24 @@
"deprecation/deprecation": "warn",
"@typescript-eslint/explicit-member-accessibility": ["warn", { "accessibility": "explicit" }],
"@typescript-eslint/switch-exhaustiveness-check": "warn",
- "node/file-extension-in-import": ["error", "always", { "tryExtensions": [".js", ".json"] }],
"import/no-commonjs": "error",
- "import/extensions": ["error", "ignorePackages"]
+ "import/extensions": ["error", "ignorePackages"],
+ "@typescript-eslint/no-restricted-imports": [
+ "error",
+ {
+ "paths": [
+ {
+ "name": "discord-api-types",
+ "message": "Please use discord-api-types/v9 instead.",
+ "allowTypeImports": true
+ },
+ {
+ "name": "discord-api-types-next",
+ "message": "Please use discord-api-types-next/v9 instead.",
+ "allowTypeImports": true
+ }
+ ]
+ }
+ ]
}
}
diff --git a/package.json b/package.json
index 3489b35..c3ea3e6 100644
--- a/package.json
+++ b/package.json
@@ -34,10 +34,11 @@
"build:esbuild": "yarn rimraf dist && yarn esbuild --sourcemap=inline --outdir=dist --platform=node --target=es2020 --format=esm --log-level=warning src/**/*.ts",
"build:tsc": "yarn rimraf dist && yarn tsc",
"build:tsc:no-emit": "yarn rimraf dist && yarn tsc --noEmit",
- "_start": "yarn build:esbuild && node --enable-source-maps --experimental-json-modules --no-warnings dist/src/bot.js",
- "start": "yarn build:tsc && node --enable-source-maps --experimental-json-modules --no-warnings dist/src/bot.js",
+ "start:raw": "node --enable-source-maps --experimental-json-modules --no-warnings dist/src/bot.js",
+ "start:esbuild": "yarn build:esbuild && yarn start:raw",
+ "start": "yarn build:tsc && yarn start:raw",
"start:dry": "yarn start dry",
- "dev": "yarn build:tsc && node --enable-source-maps --experimental-json-modules --no-warnings dist/src/bot.js",
+ "dev": "yarn build:tsc && yarn start:raw",
"test": "yarn lint && yarn tsc --noEmit",
"format": "yarn prettier . --write",
"lint": "yarn eslint --ext js,jsx,ts,tsx src",
@@ -55,14 +56,15 @@
"@notenoughupdates/humanize-duration": "^4.0.1",
"@notenoughupdates/simplify-number": "^1.0.1",
"@notenoughupdates/wolfram-alpha-api": "^1.0.1",
- "@sentry/integrations": "^6.17.6",
- "@sentry/node": "^6.17.6",
- "@sentry/tracing": "^6.17.6",
+ "@sentry/integrations": "^6.17.7",
+ "@sentry/node": "^6.17.7",
+ "@sentry/tracing": "^6.17.7",
"canvas": "^2.9.0",
"chalk": "^5.0.0",
"deep-lock": "^1.0.0",
"discord-akairo": "npm:@notenoughupdates/discord-akairo@dev",
- "discord-api-types": "0.26.1",
+ "discord-api-types": "0.27.0",
+ "discord-api-types-next": "npm:discord-api-types@next",
"discord.js": "npm:@notenoughupdates/discord.js@dev",
"fuse.js": "^6.5.3",
"got": "^12.0.1",
@@ -74,7 +76,7 @@
"pg": "^8.7.3",
"pg-hstore": "^2.3.4",
"prettier": "^2.5.1",
- "pretty-bytes": "^5.6.0",
+ "pretty-bytes": "^6.0.0",
"rimraf": "^3.0.2",
"sequelize": "6.16.1",
"tinycolor2": "^1.4.2",
@@ -83,7 +85,7 @@
},
"devDependencies": {
"@sapphire/snowflake": "^3.1.0",
- "@sentry/types": "^6.17.6",
+ "@sentry/types": "^6.17.7",
"@types/eslint": "^8.4.1",
"@types/express": "^4.17.13",
"@types/lodash": "^4.14.178",
@@ -97,12 +99,14 @@
"@types/validator": "^13.7.1",
"@typescript-eslint/eslint-plugin": "^5.11.0",
"@typescript-eslint/parser": "^5.11.0",
- "eslint": "^8.8.0",
+ "eslint": "^8.9.0",
"eslint-config-prettier": "^8.3.0",
"eslint-plugin-deprecation": "^1.3.2",
"eslint-plugin-import": "^2.25.4",
- "eslint-plugin-node": "^11.1.0",
"node-fetch": "^3.2.0"
},
+ "resolutions": {
+ "@discordjs/rest@npm:^0.4.0-dev": "0.3.0"
+ },
"packageManager": "yarn@3.1.1"
}
diff --git a/src/arguments/discordEmoji.ts b/src/arguments/discordEmoji.ts
index d9428e1..efaa4dd 100644
--- a/src/arguments/discordEmoji.ts
+++ b/src/arguments/discordEmoji.ts
@@ -1,5 +1,5 @@
-import { type BushArgumentTypeCaster } from '#lib';
-import { type Snowflake } from 'discord-api-types';
+import type { BushArgumentTypeCaster } from '#lib';
+import type { Snowflake } from 'discord-api-types';
export const discordEmoji: BushArgumentTypeCaster<DiscordEmojiInfo | null> = (_, phrase) => {
if (!phrase) return null;
diff --git a/src/commands/config/config.ts b/src/commands/config/config.ts
index 2fae2fd..5346924 100644
--- a/src/commands/config/config.ts
+++ b/src/commands/config/config.ts
@@ -354,6 +354,7 @@ export default class ConfigCommand extends BushCommand {
};
const components = new ActionRow().addComponents(
+ // @ts-expect-error: outdated @discord.js/builders
new ButtonComponent().setStyle(ButtonStyle.Primary).setCustomId('command_settingsBack').setLabel('Back')
);
settingsEmbed.setDescription(
diff --git a/src/commands/config/features.ts b/src/commands/config/features.ts
index 2e7d623..7fa82a9 100644
--- a/src/commands/config/features.ts
+++ b/src/commands/config/features.ts
@@ -90,7 +90,7 @@ export default class FeaturesCommand extends BushCommand {
.setMaxValues(1)
.setMinValues(1)
.setOptions(
- guildFeatures.map((f) =>
+ ...guildFeatures.map((f) =>
new SelectMenuOption().setLabel(guildFeaturesObj[f].name).setValue(f).setDescription(guildFeaturesObj[f].description)
)
)
diff --git a/src/commands/dev/servers.ts b/src/commands/dev/servers.ts
index 173970b..378893e 100644
--- a/src/commands/dev/servers.ts
+++ b/src/commands/dev/servers.ts
@@ -1,6 +1,6 @@
import { BushCommand, ButtonPaginator, type BushMessage, type BushSlashMessage } from '#lib';
-import { APIEmbed } from 'discord-api-types';
-import { type Guild } from 'discord.js';
+import type { APIEmbed } from 'discord-api-types';
+import type { Guild } from 'discord.js';
export default class ServersCommand extends BushCommand {
public constructor() {
diff --git a/src/commands/dev/test.ts b/src/commands/dev/test.ts
index 669001f..9784412 100644
--- a/src/commands/dev/test.ts
+++ b/src/commands/dev/test.ts
@@ -1,5 +1,4 @@
import { BushCommand, ButtonPaginator, Shared, type BushMessage } from '#lib';
-// eslint-disable-next-line node/file-extension-in-import
import { Routes } from 'discord-api-types/rest/v9';
import {
ActionRow,
@@ -55,10 +54,15 @@ export default class TestCommand extends BushCommand {
if (['button', 'buttons'].includes(args?.feature?.toLowerCase())) {
const ButtonRow = new ActionRow().addComponents(
+ // @ts-expect-error: outdated @discord.js/builders
new ButtonComponent().setStyle(ButtonStyle.Primary).setCustomId('primaryButton').setLabel('Primary'),
+ // @ts-expect-error: outdated @discord.js/builders
new ButtonComponent().setStyle(ButtonStyle.Secondary).setCustomId('secondaryButton').setLabel('Secondary'),
+ // @ts-expect-error: outdated @discord.js/builders
new ButtonComponent().setStyle(ButtonStyle.Success).setCustomId('successButton').setLabel('Success'),
+ // @ts-expect-error: outdated @discord.js/builders
new ButtonComponent().setStyle(ButtonStyle.Danger).setCustomId('dangerButton').setLabel('Danger'),
+ // @ts-expect-error: outdated @discord.js/builders
new ButtonComponent().setStyle(ButtonStyle.Link).setLabel('Link').setURL('https://www.youtube.com/watch?v=dQw4w9WgXcQ')
);
return await message.util.reply({ content: 'buttons', components: [ButtonRow] });
@@ -78,6 +82,7 @@ export default class TestCommand extends BushCommand {
.setTitle('Title');
const buttonRow = new ActionRow().addComponents(
+ // @ts-expect-error: outdated @discord.js/builders
new ButtonComponent().setStyle(ButtonStyle.Link).setLabel('Link').setURL('https://google.com/')
);
return await message.util.reply({ content: 'Test', embeds: [embed], components: [buttonRow] });
@@ -87,6 +92,7 @@ export default class TestCommand extends BushCommand {
const row = new ActionRow();
for (let b = 1; b <= 5; b++) {
const id = (a + 5 * (b - 1)).toString();
+ // @ts-expect-error: outdated @discord.js/builders
const button = new ButtonComponent().setStyle(ButtonStyle.Primary).setCustomId(id).setLabel(id);
row.addComponents(button);
}
@@ -119,6 +125,7 @@ export default class TestCommand extends BushCommand {
const row = new ActionRow();
for (let b = 1; b <= 5; b++) {
const id = (a + 5 * (b - 1)).toString();
+ // @ts-expect-error: outdated @discord.js/builders
const button = new ButtonComponent().setStyle(ButtonStyle.Secondary).setCustomId(id).setLabel(id);
row.addComponents(button);
}
@@ -151,6 +158,7 @@ export default class TestCommand extends BushCommand {
content: 'Click for modal',
components: [
new ActionRow().addComponents(
+ // @ts-expect-error: outdated @discord.js/builders
new ButtonComponent().setStyle(ButtonStyle.Primary).setLabel('Modal').setCustomId('test;modal')
)
]
diff --git a/src/commands/info/guildInfo.ts b/src/commands/info/guildInfo.ts
index a4b7fb9..ed8a973 100644
--- a/src/commands/info/guildInfo.ts
+++ b/src/commands/info/guildInfo.ts
@@ -1,6 +1,6 @@
import { BushCommand, type ArgType, type BushMessage, type BushSlashMessage, type OptionalArgType } from '#lib';
import assert from 'assert';
-import { GuildDefaultMessageNotifications, GuildExplicitContentFilter } from 'discord-api-types';
+import { GuildDefaultMessageNotifications, GuildExplicitContentFilter } from 'discord-api-types/v9';
import {
ApplicationCommandOptionType,
Embed,
diff --git a/src/commands/info/help.ts b/src/commands/info/help.ts
index 2383566..ef3ef30 100644
--- a/src/commands/info/help.ts
+++ b/src/commands/info/help.ts
@@ -143,14 +143,17 @@ export default class HelpCommand extends BushCommand {
const row = new ActionRow();
if (!client.config.isDevelopment && !client.guilds.cache.some((guild) => guild.ownerId === message.author.id)) {
+ // @ts-expect-error: outdated @discord.js/builders
row.addComponents(new ButtonComponent().setStyle(ButtonStyle.Link).setLabel('Invite Me').setURL(util.invite));
}
if (!client.guilds.cache.get(client.config.supportGuild.id)?.members.cache.has(message.author.id)) {
row.addComponents(
+ // @ts-expect-error: outdated @discord.js/builders
new ButtonComponent().setStyle(ButtonStyle.Link).setLabel('Support Server').setURL(client.config.supportGuild.invite)
);
}
if (packageDotJSON?.repository)
+ // @ts-expect-error: outdated @discord.js/builders
row.addComponents(new ButtonComponent().setStyle(ButtonStyle.Link).setLabel('GitHub').setURL(packageDotJSON.repository));
else void message.channel?.send('Error importing package.json, please report this to my developer.');
diff --git a/src/commands/info/links.ts b/src/commands/info/links.ts
index 25b040c..d9d5b8a 100644
--- a/src/commands/info/links.ts
+++ b/src/commands/info/links.ts
@@ -22,10 +22,13 @@ export default class LinksCommand extends BushCommand {
public override async exec(message: BushMessage | BushSlashMessage) {
const buttonRow = new ActionRow();
if (!client.config.isDevelopment || message.author.isOwner()) {
+ // @ts-expect-error: outdated @discord.js/builders
buttonRow.addComponents(new ButtonComponent().setStyle(ButtonStyle.Link).setLabel('Invite Me').setURL(util.invite));
}
buttonRow.addComponents(
+ // @ts-expect-error: outdated @discord.js/builders
new ButtonComponent().setStyle(ButtonStyle.Link).setLabel('Support Server').setURL(client.config.supportGuild.invite),
+ // @ts-expect-error: outdated @discord.js/builders
new ButtonComponent().setStyle(ButtonStyle.Link).setLabel('GitHub').setURL(packageDotJSON.repository)
);
return await message.util.reply({ content: 'Here are some useful links:', components: [buttonRow] });
diff --git a/src/commands/info/userInfo.ts b/src/commands/info/userInfo.ts
index 97cdc30..02a3be6 100644
--- a/src/commands/info/userInfo.ts
+++ b/src/commands/info/userInfo.ts
@@ -7,7 +7,7 @@ import {
type BushSlashMessage,
type BushUser
} from '#lib';
-import { APIApplication, TeamMemberMembershipState } from 'discord-api-types';
+import { TeamMemberMembershipState, type APIApplication } from 'discord-api-types/v9';
import {
ActivityType,
ApplicationCommandOptionType,
diff --git a/src/commands/moulberry-bush/capes.ts b/src/commands/moulberry-bush/capes.ts
index 032f62d..47a4ea6 100644
--- a/src/commands/moulberry-bush/capes.ts
+++ b/src/commands/moulberry-bush/capes.ts
@@ -1,6 +1,6 @@
import { BushCommand, ButtonPaginator, DeleteButton, type BushMessage, type OptionalArgType } from '#lib';
import assert from 'assert';
-import { APIEmbed } from 'discord-api-types';
+import { APIEmbed } from 'discord-api-types/v9';
import { ApplicationCommandOptionType, AutocompleteInteraction, PermissionFlagsBits } from 'discord.js';
import Fuse from 'fuse.js';
import got from 'got';
diff --git a/src/commands/utilities/highlight-!.ts b/src/commands/utilities/highlight-!.ts
index 332af03..687990f 100644
--- a/src/commands/utilities/highlight-!.ts
+++ b/src/commands/utilities/highlight-!.ts
@@ -1,6 +1,6 @@
import { BushCommand, Highlight, HighlightWord, type BushSlashMessage } from '#lib';
import { Flag, type ArgumentGeneratorReturn, type SlashOption } from 'discord-akairo';
-import { ApplicationCommandOptionType } from 'discord-api-types';
+import { ApplicationCommandOptionType } from 'discord-api-types/v9';
import { ApplicationCommandSubCommandData, AutocompleteInteraction, CacheType } from 'discord.js';
type Unpacked<T> = T extends (infer U)[] ? U : T;
diff --git a/src/commands/utilities/reminders.ts b/src/commands/utilities/reminders.ts
index 509da67..10206c1 100644
--- a/src/commands/utilities/reminders.ts
+++ b/src/commands/utilities/reminders.ts
@@ -1,6 +1,6 @@
import { BushCommand, ButtonPaginator, Reminder, type BushMessage, type BushSlashMessage } from '#lib';
import assert from 'assert';
-import { APIEmbed } from 'discord-api-types';
+import { APIEmbed } from 'discord-api-types/v9';
import { PermissionFlagsBits } from 'discord.js';
import { Op } from 'sequelize';
diff --git a/src/lib/common/AutoMod.ts b/src/lib/common/AutoMod.ts
index 784085d..9024260 100644
--- a/src/lib/common/AutoMod.ts
+++ b/src/lib/common/AutoMod.ts
@@ -156,6 +156,7 @@ export class AutoMod {
? [
new ActionRow().addComponents(
new ButtonComponent()
+ // @ts-expect-error: outdated @discord.js/builders
.setStyle(ButtonStyle.Danger)
.setLabel('Ban User')
.setCustomId(`automod;ban;${this.message.author.id};everyone mention and scam phrase`)
@@ -277,6 +278,7 @@ export class AutoMod {
? [
new ActionRow().addComponents(
new ButtonComponent()
+ // @ts-expect-error: outdated @discord.js/builders
.setStyle(ButtonStyle.Danger)
.setLabel('Ban User')
.setCustomId(`automod;ban;${this.message.author.id};${highestOffence.reason}`)
diff --git a/src/lib/common/ButtonPaginator.ts b/src/lib/common/ButtonPaginator.ts
index 0399e74..09e059c 100644
--- a/src/lib/common/ButtonPaginator.ts
+++ b/src/lib/common/ButtonPaginator.ts
@@ -1,6 +1,6 @@
import { DeleteButton, type BushMessage, type BushSlashMessage } from '#lib';
import { CommandUtil } from 'discord-akairo';
-import { APIEmbed } from 'discord-api-types';
+import { APIEmbed } from 'discord-api-types/v9';
import { ActionRow, ActionRowComponent, ButtonComponent, ButtonStyle, Embed, type MessageComponentInteraction } from 'discord.js';
/**
@@ -173,26 +173,31 @@ export class ButtonPaginator {
protected getPaginationRow(disableAll = false): ActionRow<ActionRowComponent> {
return new ActionRow().addComponents(
new ButtonComponent()
+ // @ts-expect-error: outdated @discord.js/builders
.setStyle(ButtonStyle.Primary)
.setCustomId('paginate_beginning')
.setEmoji(PaginateEmojis.BEGINNING)
.setDisabled(disableAll || this.curPage === 0),
new ButtonComponent()
+ // @ts-expect-error: outdated @discord.js/builders
.setStyle(ButtonStyle.Primary)
.setCustomId('paginate_back')
.setEmoji(PaginateEmojis.BACK)
.setDisabled(disableAll || this.curPage === 0),
new ButtonComponent()
+ // @ts-expect-error: outdated @discord.js/builders
.setStyle(ButtonStyle.Primary)
.setCustomId('paginate_stop')
.setEmoji(PaginateEmojis.STOP)
.setDisabled(disableAll),
new ButtonComponent()
+ // @ts-expect-error: outdated @discord.js/builders
.setStyle(ButtonStyle.Primary)
.setCustomId('paginate_next')
.setEmoji(PaginateEmojis.FORWARD)
.setDisabled(disableAll || this.curPage === this.embeds.length - 1),
new ButtonComponent()
+ // @ts-expect-error: outdated @discord.js/builders
.setStyle(ButtonStyle.Primary)
.setCustomId('paginate_end')
.setEmoji(PaginateEmojis.END)
diff --git a/src/lib/common/ConfirmationPrompt.ts b/src/lib/common/ConfirmationPrompt.ts
index bd11c5c..1f027ef 100644
--- a/src/lib/common/ConfirmationPrompt.ts
+++ b/src/lib/common/ConfirmationPrompt.ts
@@ -31,11 +31,13 @@ export class ConfirmationPrompt {
this.messageOptions.components = [
new ActionRow().addComponents(
new ButtonComponent()
+ // @ts-expect-error: outdated @discord.js/builders
.setStyle(ButtonStyle.Primary)
.setCustomId('confirmationPrompt_confirm')
.setEmoji({ id: util.emojisRaw.successFull, name: 'successFull', animated: false })
.setLabel('Yes'),
new ButtonComponent()
+ // @ts-expect-error: outdated @discord.js/builders
.setStyle(ButtonStyle.Danger)
.setCustomId('confirmationPrompt_cancel')
.setEmoji({ id: util.emojisRaw.errorFull, name: 'errorFull', animated: false })
diff --git a/src/lib/common/DeleteButton.ts b/src/lib/common/DeleteButton.ts
index cf3b416..f2e0ff3 100644
--- a/src/lib/common/DeleteButton.ts
+++ b/src/lib/common/DeleteButton.ts
@@ -68,6 +68,7 @@ export class DeleteButton {
this.messageOptions.components = [
new ActionRow().addComponents(
new ButtonComponent()
+ // @ts-expect-error: outdated @discord.js/builders
.setStyle(ButtonStyle.Primary)
.setCustomId('paginate__stop')
.setEmoji(PaginateEmojis.STOP)
diff --git a/src/lib/common/util/Moderation.ts b/src/lib/common/util/Moderation.ts
index 0ba6fca..c2236ab 100644
--- a/src/lib/common/util/Moderation.ts
+++ b/src/lib/common/util/Moderation.ts
@@ -10,7 +10,33 @@ import {
type BushUserResolvable,
type ModLogType
} from '#lib';
-import { Embed, PermissionFlagsBits, type Snowflake } from 'discord.js';
+import assert from 'assert';
+import { ActionRow, ButtonComponent, ButtonStyle, ComponentType, Embed, PermissionFlagsBits, type Snowflake } from 'discord.js';
+
+enum punishMap {
+ 'warned' = 'warn',
+ 'muted' = 'mute',
+ 'unmuted' = 'unmute',
+ 'kicked' = 'kick',
+ 'banned' = 'ban',
+ 'unbanned' = 'unban',
+ 'timedout' = 'timeout',
+ 'untimedout' = 'untimeout',
+ 'blocked' = 'block',
+ 'unblocked' = 'unblock'
+}
+enum reversedPunishMap {
+ 'warn' = 'warned',
+ 'mute' = 'muted',
+ 'unmute' = 'unmuted',
+ 'kick' = 'kicked',
+ 'ban' = 'banned',
+ 'unban' = 'unbanned',
+ 'timeout' = 'timedout',
+ 'untimeout' = 'untimedout',
+ 'block' = 'blocked',
+ 'unblock' = 'unblocked'
+}
/**
* A utility class with moderation-related methods.
@@ -204,6 +230,19 @@ export class Moderation {
return typeMap[type];
}
+ public static punishmentToPresentTense(punishment: PunishmentTypeDM): PunishmentTypePresent {
+ return punishMap[punishment];
+ }
+
+ public static punishmentToPastTense(punishment: PunishmentTypePresent): PunishmentTypeDM {
+ return reversedPunishMap[punishment];
+ }
+
+ /**
+ * Notifies the specified user of their punishment.
+ * @param options Options for notifying the user.
+ * @returns Whether or not the dm was successfully sent.
+ */
public static async punishDM(options: PunishDMOptions): Promise<boolean> {
const ending = await options.guild.getSetting('punishmentEnding');
const dmEmbed =
@@ -211,16 +250,45 @@ export class Moderation {
? new Embed().setDescription(ending).setColor(util.colors.newBlurple)
: undefined;
+ const appealsEnabled = !!(
+ (await options.guild.hasFeature('punishmentAppeals')) && (await options.guild.getLogChannel('appeals'))
+ );
+
+ let content = `You have been ${options.punishment} `;
+ if (options.punishment.includes('blocked')) {
+ assert(options.channel);
+ content += `from <#${options.channel}> `;
+ }
+ content += `in ${util.format.input(options.guild.name)} `;
+ if (options.duration !== null && options.duration !== undefined)
+ content += options.duration ? `for ${util.humanizeDuration(options.duration)} ` : 'permanently ';
+ const reason = options.reason?.trim() ? options.reason?.trim() : 'No reason provided';
+ content += `for ${util.format.input(reason)}.`;
+
+ let components;
+ if (appealsEnabled && options.modlog)
+ components = [
+ new ActionRow({
+ type: ComponentType.ActionRow,
+ components: [
+ // @ts-expect-error: outdated @discord.js/builders
+ new ButtonComponent({
+ custom_id: `appeal;${this.punishmentToPresentTense(options.punishment)};${
+ options.guild.id
+ };${client.users.resolveId(options.user)};${options.modlog}`,
+ style: ButtonStyle.Primary,
+ type: ComponentType.Button,
+ label: 'Appeal'
+ })
+ ]
+ })
+ ];
+
const dmSuccess = await client.users
.send(options.user, {
- content: `You have been ${options.punishment} in **${options.guild.name}** ${
- options.duration !== null && options.duration !== undefined
- ? options.duration
- ? `for ${util.humanizeDuration(options.duration)} `
- : 'permanently '
- : ''
- }for **${options.reason?.trim() ? options.reason?.trim() : 'No reason provided'}**.`,
- embeds: dmEmbed ? [dmEmbed] : undefined
+ content,
+ embeds: dmEmbed ? [dmEmbed] : undefined,
+ components
})
.catch(() => false);
return !!dmSuccess;
@@ -342,6 +410,11 @@ export interface RemovePunishmentEntryOptions {
*/
export interface PunishDMOptions {
/**
+ * The modlog case id so the user can make an appeal.
+ */
+ modlog?: string;
+
+ /**
* The guild that the punishment is taking place in.
*/
guild: BushGuild;
@@ -354,7 +427,7 @@ export interface PunishDMOptions {
/**
* The punishment that the user has received.
*/
- punishment: string;
+ punishment: PunishmentTypeDM;
/**
* The reason the user's punishment.
@@ -371,4 +444,35 @@ export interface PunishDMOptions {
* @default true
*/
sendFooter: boolean;
+
+ /**
+ * The channel that the user was (un)blocked from.
+ */
+ channel?: Snowflake;
}
+
+export type PunishmentTypeDM =
+ | 'warned'
+ | 'muted'
+ | 'unmuted'
+ | 'kicked'
+ | 'banned'
+ | 'unbanned'
+ | 'timedout'
+ | 'untimedout'
+ | 'blocked'
+ | 'unblocked';
+
+export type PunishmentTypePresent =
+ | 'warn'
+ | 'mute'
+ | 'unmute'
+ | 'kick'
+ | 'ban'
+ | 'unban'
+ | 'timeout'
+ | 'untimeout'
+ | 'block'
+ | 'unblock';
+
+export type AppealButtonId = `appeal;${PunishmentTypePresent};${Snowflake};${Snowflake};${string}`;
diff --git a/src/lib/extensions/discord-akairo/BushClientUtil.ts b/src/lib/extensions/discord-akairo/BushClientUtil.ts
index 41d16f7..bf4dfaf 100644
--- a/src/lib/extensions/discord-akairo/BushClientUtil.ts
+++ b/src/lib/extensions/discord-akairo/BushClientUtil.ts
@@ -21,7 +21,7 @@ import assert from 'assert';
import { exec } from 'child_process';
import deepLock from 'deep-lock';
import { ClientUtil, Util as AkairoUtil } from 'discord-akairo';
-import { APIMessage } from 'discord-api-types';
+import type { APIMessage } from 'discord-api-types/v9';
import {
Constants as DiscordConstants,
GuildMember,
diff --git a/src/lib/extensions/discord-akairo/BushCommand.ts b/src/lib/extensions/discord-akairo/BushCommand.ts
index 650b538..ff3748e 100644
--- a/src/lib/extensions/discord-akairo/BushCommand.ts
+++ b/src/lib/extensions/discord-akairo/BushCommand.ts
@@ -44,7 +44,7 @@ import {
type ContextMenuCommand,
type MissingPermissionSupplier,
type SlashOption,
- type SlashResolveTypes
+ type SlashResolveType
} from 'discord-akairo';
import {
type ApplicationCommandOptionChoice,
@@ -147,7 +147,7 @@ interface BaseBushArgumentOptions extends Omit<ArgumentOptions, 'type' | 'prompt
*
* ex. get the resolved member object when the type is `USER`
*/
- slashResolve?: SlashResolveTypes;
+ slashResolve?: SlashResolveType;
/**
* The choices of the option for the user to pick from
@@ -340,7 +340,7 @@ export interface ArgsInfo {
description: string;
optional?: boolean;
slashType: AkairoApplicationCommandOptionData['type'] | false;
- slashResolve?: SlashResolveTypes;
+ slashResolve?: SlashResolveType;
only?: 'slash' | 'text';
type: string;
}
diff --git a/src/lib/extensions/discord.js/BushGuild.ts b/src/lib/extensions/discord.js/BushGuild.ts
index 93875b8..80799fd 100644
--- a/src/lib/extensions/discord.js/BushGuild.ts
+++ b/src/lib/extensions/discord.js/BushGuild.ts
@@ -173,8 +173,22 @@ export class BushGuild extends Guild {
if ((await this.bans.fetch()).has(user.id)) return banResponse.ALREADY_BANNED;
const ret = await (async () => {
+ // add modlog entry
+ const { log: modlog } = await Moderation.createModLogEntry({
+ type: options.duration ? ModLogType.TEMP_BAN : ModLogType.PERM_BAN,
+ user: user,
+ moderator: moderator.id,
+ reason: options.reason,
+ duration: options.duration,
+ guild: this,
+ evidence: options.evidence
+ });
+ if (!modlog) return banResponse.MODLOG_ERROR;
+ caseID = modlog.id;
+
// dm user
dmSuccessEvent = await Moderation.punishDM({
+ modlog: modlog.id,
guild: this,
user: user,
punishment: 'banned',
@@ -187,24 +201,11 @@ export class BushGuild extends Guild {
const banSuccess = await this.bans
.create(user?.id ?? options.user, {
reason: `${moderator.tag} | ${options.reason ?? 'No reason provided.'}`,
- days: options.deleteDays
+ deleteMessageDays: options.deleteDays
})
.catch(() => false);
if (!banSuccess) return banResponse.ACTION_ERROR;
- // add modlog entry
- const { log: modlog } = await Moderation.createModLogEntry({
- type: options.duration ? ModLogType.TEMP_BAN : ModLogType.PERM_BAN,
- user: user,
- moderator: moderator.id,
- reason: options.reason,
- duration: options.duration,
- guild: this,
- evidence: options.evidence
- });
- if (!modlog) return banResponse.MODLOG_ERROR;
- caseID = modlog.id;
-
// add punishment entry so they can be unbanned later
const punishmentEntrySuccess = await Moderation.createPunishmentEntry({
type: 'ban',
diff --git a/src/lib/extensions/discord.js/BushGuildMember.ts b/src/lib/extensions/discord.js/BushGuildMember.ts
index 84fdf13..5d7144b 100644
--- a/src/lib/extensions/discord.js/BushGuildMember.ts
+++ b/src/lib/extensions/discord.js/BushGuildMember.ts
@@ -3,6 +3,8 @@ import {
BushClientEvents,
Moderation,
ModLogType,
+ PunishmentTypeDM,
+ Time,
type BushClient,
type BushGuild,
type BushGuildTextBasedChannel,
@@ -29,14 +31,29 @@ export class BushGuildMember extends GuildMember {
/**
* Send a punishment dm to the user.
+ * @param modlog The modlog case id so the user can make an appeal.
* @param punishment The punishment that the user has received.
* @param reason The reason for the user's punishment.
* @param duration The duration of the punishment.
* @param sendFooter Whether or not to send the guild's punishment footer with the dm.
* @returns Whether or not the dm was sent successfully.
*/
- public async bushPunishDM(punishment: string, reason?: string | null, duration?: number, sendFooter = true): Promise<boolean> {
- return Moderation.punishDM({ guild: this.guild, user: this, punishment, reason: reason ?? undefined, duration, sendFooter });
+ public async bushPunishDM(
+ punishment: PunishmentTypeDM,
+ reason?: string | null,
+ duration?: number,
+ modlog?: string,
+ sendFooter = true
+ ): Promise<boolean> {
+ return Moderation.punishDM({
+ modlog,
+ guild: this.guild,
+ user: this,
+ punishment,
+ reason: reason ?? undefined,
+ duration,
+ sendFooter
+ });
}
/**
@@ -304,7 +321,7 @@ export class BushGuildMember extends GuildMember {
if (!options.silent) {
// dm user
- const dmSuccess = await this.bushPunishDM('muted', options.reason, options.duration ?? 0);
+ const dmSuccess = await this.bushPunishDM('muted', options.reason, options.duration ?? 0, modlog.id);
dmSuccessEvent = dmSuccess;
if (!dmSuccess) return muteResponse.DM_ERROR;
}
@@ -386,7 +403,7 @@ export class BushGuildMember extends GuildMember {
if (!options.silent) {
// dm user
- const dmSuccess = await this.bushPunishDM('unmuted', options.reason, undefined, false);
+ const dmSuccess = await this.bushPunishDM('unmuted', options.reason, undefined, '', false);
dmSuccessEvent = dmSuccess;
if (!dmSuccess) return unmuteResponse.DM_ERROR;
}
@@ -429,14 +446,6 @@ export class BushGuildMember extends GuildMember {
const moderator = await util.resolveNonCachedUser(options.moderator ?? this.guild.me);
if (!moderator) return kickResponse.CANNOT_RESOLVE_USER;
const ret = await (async () => {
- // dm user
- const dmSuccess = options.silent ? null : await this.bushPunishDM('kicked', options.reason);
- dmSuccessEvent = dmSuccess ?? undefined;
-
- // kick
- const kickSuccess = await this.kick(`${moderator?.tag} | ${options.reason ?? 'No reason provided.'}`).catch(() => false);
- if (!kickSuccess) return kickResponse.ACTION_ERROR;
-
// add modlog entry
const { log: modlog } = await Moderation.createModLogEntry({
type: ModLogType.KICK,
@@ -449,6 +458,15 @@ export class BushGuildMember extends GuildMember {
});
if (!modlog) return kickResponse.MODLOG_ERROR;
caseID = modlog.id;
+
+ // dm user
+ const dmSuccess = options.silent ? null : await this.bushPunishDM('kicked', options.reason, undefined, modlog.id);
+ dmSuccessEvent = dmSuccess ?? undefined;
+
+ // kick
+ const kickSuccess = await this.kick(`${moderator?.tag} | ${options.reason ?? 'No reason provided.'}`).catch(() => false);
+ if (!kickSuccess) return kickResponse.ACTION_ERROR;
+
if (dmSuccess === false) return kickResponse.DM_ERROR;
return kickResponse.SUCCESS;
})();
@@ -489,17 +507,6 @@ export class BushGuildMember extends GuildMember {
});
const ret = await (async () => {
- // dm user
- const dmSuccess = options.silent ? null : await this.bushPunishDM('banned', options.reason, options.duration ?? 0);
- dmSuccessEvent = dmSuccess ?? undefined;
-
- // ban
- const banSuccess = await this.ban({
- reason: `${moderator.tag} | ${options.reason ?? 'No reason provided.'}`,
- days: options.deleteDays
- }).catch(() => false);
- if (!banSuccess) return banResponse.ACTION_ERROR;
-
// add modlog entry
const { log: modlog } = await Moderation.createModLogEntry({
type: options.duration ? ModLogType.TEMP_BAN : ModLogType.PERM_BAN,
@@ -514,6 +521,19 @@ export class BushGuildMember extends GuildMember {
if (!modlog) return banResponse.MODLOG_ERROR;
caseID = modlog.id;
+ // dm user
+ const dmSuccess = options.silent
+ ? null
+ : await this.bushPunishDM('banned', options.reason, options.duration ?? 0, modlog.id);
+ dmSuccessEvent = dmSuccess ?? undefined;
+
+ // ban
+ const banSuccess = await this.ban({
+ reason: `${moderator.tag} | ${options.reason ?? 'No reason provided.'}`,
+ deleteMessageDays: options.deleteDays
+ }).catch(() => false);
+ if (!banSuccess) return banResponse.ACTION_ERROR;
+
// add punishment entry so they can be unbanned later
const punishmentEntrySuccess = await Moderation.createPunishmentEntry({
type: 'ban',
@@ -595,20 +615,21 @@ export class BushGuildMember extends GuildMember {
});
if (!punishmentEntrySuccess) return blockResponse.PUNISHMENT_ENTRY_ADD_ERROR;
- if (!options.silent) {
- // dm user
- const dmSuccess = await this.send({
- content: `You have been blocked from <#${channel.id}> in **${this.guild.name}** ${
- options.duration !== null && options.duration !== undefined
- ? options.duration
- ? `for ${util.humanizeDuration(options.duration)} `
- : 'permanently '
- : ''
- }for **${options.reason?.trim() ? options.reason?.trim() : 'No reason provided'}**.`
- }).catch(() => false);
- dmSuccessEvent = !!dmSuccess;
- if (!dmSuccess) return blockResponse.DM_ERROR;
- }
+ // dm user
+ const dmSuccess = options.silent
+ ? null
+ : await Moderation.punishDM({
+ punishment: 'blocked',
+ reason: options.reason ?? undefined,
+ duration: options.duration ?? 0,
+ modlog: modlog.id,
+ guild: this.guild,
+ user: this,
+ sendFooter: true,
+ channel: channel.id
+ });
+ dmSuccessEvent = !!dmSuccess;
+ if (!dmSuccess) return blockResponse.DM_ERROR;
return blockResponse.SUCCESS;
})();
@@ -683,16 +704,22 @@ export class BushGuildMember extends GuildMember {
});
if (!punishmentEntrySuccess) return unblockResponse.ACTION_ERROR;
- if (!options.silent) {
- // dm user
- const dmSuccess = await this.send({
- content: `You have been unblocked from <#${channel.id}> in **${this.guild.name}** for **${
- options.reason?.trim() ? options.reason?.trim() : 'No reason provided'
- }**.`
- }).catch(() => false);
- dmSuccessEvent = !!dmSuccess;
- if (!dmSuccess) return unblockResponse.DM_ERROR;
- }
+ // dm user
+ const dmSuccess = options.silent
+ ? null
+ : await Moderation.punishDM({
+ punishment: 'unblocked',
+ reason: options.reason ?? undefined,
+ guild: this.guild,
+ user: this,
+ sendFooter: false,
+ channel: channel.id
+ });
+ dmSuccessEvent = !!dmSuccess;
+ if (!dmSuccess) return blockResponse.DM_ERROR;
+
+ dmSuccessEvent = !!dmSuccess;
+ if (!dmSuccess) return unblockResponse.DM_ERROR;
return unblockResponse.SUCCESS;
})();
@@ -723,7 +750,7 @@ export class BushGuildMember extends GuildMember {
// checks
if (!this.guild.me!.permissions.has(PermissionFlagsBits.ModerateMembers)) return timeoutResponse.MISSING_PERMISSIONS;
- const twentyEightDays = client.consts.timeUnits.days.value * 28;
+ const twentyEightDays = Time.Day * 28;
if (options.duration > twentyEightDays) return timeoutResponse.INVALID_DURATION;
let caseID: string | undefined = undefined;
@@ -756,7 +783,7 @@ export class BushGuildMember extends GuildMember {
if (!options.silent) {
// dm user
- const dmSuccess = await this.bushPunishDM('timed out', options.reason, options.duration);
+ const dmSuccess = await this.bushPunishDM('timedout', options.reason, options.duration, modlog.id);
dmSuccessEvent = dmSuccess;
if (!dmSuccess) return timeoutResponse.DM_ERROR;
}
@@ -815,7 +842,7 @@ export class BushGuildMember extends GuildMember {
if (!options.silent) {
// dm user
- const dmSuccess = await this.bushPunishDM('untimedout', options.reason);
+ const dmSuccess = await this.bushPunishDM('untimedout', options.reason, undefined, '', false);
dmSuccessEvent = dmSuccess;
if (!dmSuccess) return removeTimeoutResponse.DM_ERROR;
}
diff --git a/src/lib/models/instance/Guild.ts b/src/lib/models/instance/Guild.ts
index b41eb9e..b81562c 100644
--- a/src/lib/models/instance/Guild.ts
+++ b/src/lib/models/instance/Guild.ts
@@ -385,6 +385,11 @@ export const guildFeaturesObj = asGuildFeature({
name: 'Log Manual Punishments',
description: "Adds manual punishment to the user's modlogs and the logging channels.",
default: true
+ },
+ punishmentAppeals: {
+ name: 'Punishment Appeals',
+ description: 'Allow users to appeal their punishments and send the appeal to the configured channel.',
+ default: false
}
});
@@ -404,6 +409,10 @@ export const guildLogsObj = {
error: {
description: 'Logs errors that occur with the bot.',
configurable: true
+ },
+ appeals: {
+ description: 'Where punishment appeals are sent.',
+ configurable: true
}
};
diff --git a/src/lib/utils/BushConstants.ts b/src/lib/utils/BushConstants.ts
index 4327fec..93de100 100644
--- a/src/lib/utils/BushConstants.ts
+++ b/src/lib/utils/BushConstants.ts
@@ -317,7 +317,6 @@ export class BushConstants {
},
userFlags: {
- None: '',
Staff: '<:discordEmployee:848742947826434079>',
Partner: '<:partneredServerOwner:848743051593777152>',
Hypesquad: '<:hypeSquadEvents:848743108283072553>',
@@ -331,7 +330,8 @@ export class BushConstants {
VerifiedBot: '<:verifiedbot_rebrand1:938928232667947028><:verifiedbot_rebrand2:938928355707879475>',
VerifiedDeveloper: '<:earlyVerifiedBotDeveloper:848741079875846174>',
CertifiedModerator: '<:discordCertifiedModerator:877224285901582366>',
- BotHTTPInteractions: 'BotHTTPInteractions'
+ BotHTTPInteractions: 'BotHTTPInteractions',
+ Spammer: 'Spammer'
},
status: {
diff --git a/src/listeners/client/interactionCreate.ts b/src/listeners/client/interactionCreate.ts
index 636bb6e..40315a0 100644
--- a/src/listeners/client/interactionCreate.ts
+++ b/src/listeners/client/interactionCreate.ts
@@ -20,7 +20,7 @@ export default class InteractionCreateListener extends BushListener {
return;
} else if (interaction.isButton()) {
const id = interaction.customId;
- if (id.startsWith('paginate_') || id.startsWith('command_') || id.startsWith('confirmationPrompt_')) return;
+ if (['paginate_', 'command_', 'confirmationPrompt_', 'appeal'].some((s) => id.startsWith(s))) return;
else if (id.startsWith('automod;')) void AutoMod.handleInteraction(interaction as BushButtonInteraction);
else return await interaction.reply({ content: 'Buttons go brrr', ephemeral: true });
} else if (interaction.isSelectMenu()) {
diff --git a/src/listeners/track-manual-punishments/modlogSyncBan.ts b/src/listeners/track-manual-punishments/modlogSyncBan.ts
index 9886530..b68de7c 100644
--- a/src/listeners/track-manual-punishments/modlogSyncBan.ts
+++ b/src/listeners/track-manual-punishments/modlogSyncBan.ts
@@ -1,5 +1,5 @@
import { BushListener, BushUser, Moderation, ModLogType, Time, type BushClientEvents } from '#lib';
-import { AuditLogEvent } from 'discord-api-types';
+import { AuditLogEvent } from 'discord-api-types/v9';
import { Embed, PermissionFlagsBits } from 'discord.js';
export default class ModlogSyncBanListener extends BushListener {
diff --git a/src/listeners/track-manual-punishments/modlogSyncKick.ts b/src/listeners/track-manual-punishments/modlogSyncKick.ts
index b7762db..6ff9bd6 100644
--- a/src/listeners/track-manual-punishments/modlogSyncKick.ts
+++ b/src/listeners/track-manual-punishments/modlogSyncKick.ts
@@ -1,5 +1,5 @@
import { BushListener, BushUser, Moderation, ModLogType, Time, type BushClientEvents } from '#lib';
-import { AuditLogEvent } from 'discord-api-types';
+import { AuditLogEvent } from 'discord-api-types/v9';
import { Embed, PermissionFlagsBits } from 'discord.js';
export default class ModlogSyncKickListener extends BushListener {
diff --git a/src/listeners/track-manual-punishments/modlogSyncTimeout.ts b/src/listeners/track-manual-punishments/modlogSyncTimeout.ts
index 21dde1a..993002e 100644
--- a/src/listeners/track-manual-punishments/modlogSyncTimeout.ts
+++ b/src/listeners/track-manual-punishments/modlogSyncTimeout.ts
@@ -1,5 +1,5 @@
import { BushListener, BushUser, Moderation, ModLogType, Time, type BushClientEvents } from '#lib';
-import { AuditLogEvent } from 'discord-api-types';
+import { AuditLogEvent } from 'discord-api-types/v9';
import { Embed, PermissionFlagsBits } from 'discord.js';
export default class ModlogSyncTimeoutListener extends BushListener {
diff --git a/src/listeners/track-manual-punishments/modlogSyncUnban.ts b/src/listeners/track-manual-punishments/modlogSyncUnban.ts
index a268ef4..366d072 100644
--- a/src/listeners/track-manual-punishments/modlogSyncUnban.ts
+++ b/src/listeners/track-manual-punishments/modlogSyncUnban.ts
@@ -1,5 +1,5 @@
import { BushListener, BushUser, Moderation, ModLogType, Time, type BushClientEvents } from '#lib';
-import { AuditLogEvent } from 'discord-api-types';
+import { AuditLogEvent } from 'discord-api-types/v9';
import { Embed, PermissionFlagsBits } from 'discord.js';
export default class ModlogSyncUnbanListener extends BushListener {
diff --git a/src/listeners/ws/INTERACTION_CREATE.ts b/src/listeners/ws/INTERACTION_CREATE.ts
index a7c8a45..fd79529 100644
--- a/src/listeners/ws/INTERACTION_CREATE.ts
+++ b/src/listeners/ws/INTERACTION_CREATE.ts
@@ -1,6 +1,29 @@
-import { BushListener } from '#lib';
-// eslint-disable-next-line node/file-extension-in-import
-import { GatewayDispatchEvents, Routes } from 'discord-api-types/v9';
+import { BushListener, BushUser, Moderation, ModLog, PunishmentTypePresent } from '#lib';
+import assert from 'assert';
+import { TextInputStyle } from 'discord-api-types-next/v9';
+import {
+ APIBaseInteraction,
+ APIEmbed,
+ APIInteraction as DiscordAPITypesAPIInteraction,
+ APIInteractionResponseChannelMessageWithSource,
+ APIInteractionResponseDeferredMessageUpdate,
+ APIInteractionResponseUpdateMessage,
+ APIModalInteractionResponse,
+ APIModalSubmission,
+ ButtonStyle,
+ ComponentType,
+ GatewayDispatchEvents,
+ InteractionResponseType,
+ InteractionType,
+ Routes
+} from 'discord-api-types/v9';
+import { ActionRow, ButtonComponent, Embed, Snowflake } from 'discord.js';
+
+// todo: use from discord-api-types once updated
+export type APIModalSubmitInteraction = APIBaseInteraction<InteractionType.ModalSubmit, APIModalSubmission> &
+ Required<Pick<APIBaseInteraction<InteractionType.ModalSubmit, APIModalSubmission>, 'data'>>;
+
+export type APIInteraction = DiscordAPITypesAPIInteraction | APIModalSubmitInteraction;
export default class WsInteractionCreateListener extends BushListener {
public constructor() {
@@ -11,15 +34,218 @@ export default class WsInteractionCreateListener extends BushListener {
});
}
- public override async exec(interaction: any) {
- // console.dir(interaction);
+ public override async exec(interaction: APIInteraction) {
+ console.dir(interaction);
- if (interaction.type === 5) {
- await this.client.rest.post(Routes.interactionCallback(interaction.id, interaction.token), {
- body: {
- type: 6
- }
+ const respond = (
+ options:
+ | APIModalInteractionResponse
+ | APIInteractionResponseDeferredMessageUpdate
+ | APIInteractionResponseChannelMessageWithSource
+ | APIInteractionResponseUpdateMessage
+ ) => {
+ return this.client.rest.post(
+ Routes.interactionCallback(interaction.id, interaction.token),
+ options ? { body: options } : undefined
+ );
+ };
+
+ const deferredMessageUpdate = () => {
+ return respond({
+ type: InteractionResponseType.DeferredMessageUpdate
});
+ };
+
+ if (interaction.type === InteractionType.MessageComponent) {
+ if (interaction.data.custom_id.startsWith('appeal;')) {
+ const [, punishment, guildId, userId, modlogCase] = interaction.data.custom_id.split(';') as [
+ 'appeal',
+ PunishmentTypePresent,
+ Snowflake,
+ Snowflake,
+ string
+ ];
+
+ const guild = client.guilds.resolve(guildId);
+ if (!guild)
+ return respond({
+ type: InteractionResponseType.ChannelMessageWithSource,
+ data: {
+ content: `${util.emojis.error} I am no longer in that server.`
+ }
+ });
+
+ const modal: APIModalInteractionResponse = {
+ type: InteractionResponseType.Modal,
+ data: {
+ custom_id: `appeal_submit;${punishment};${guildId};${userId};${modlogCase}`,
+ title: `${util.capitalize(punishment)} Appeal`,
+ components: [
+ {
+ type: ComponentType.ActionRow,
+ components: [
+ {
+ type: ComponentType.TextInput,
+ style: TextInputStyle.Paragraph,
+ max_length: 1024,
+ required: true,
+ label: `Why were you ${Moderation.punishmentToPastTense(punishment)}?`,
+ placeholder: `Why do you think you received a ${punishment}?`,
+ custom_id: 'appeal_reason'
+ }
+ ]
+ },
+ {
+ type: ComponentType.ActionRow,
+ components: [
+ {
+ type: ComponentType.TextInput,
+ style: TextInputStyle.Paragraph,
+ max_length: 1024,
+ required: true,
+ label: 'Do you believe it was fair?',
+ placeholder: `Why do you think you received a ${punishment}?`,
+ custom_id: 'appeal_fair'
+ }
+ ]
+ },
+ {
+ type: ComponentType.ActionRow,
+ components: [
+ {
+ type: ComponentType.TextInput,
+ style: TextInputStyle.Paragraph,
+ max_length: 1024,
+ required: true,
+ label: `Why should your ${punishment} be removed?`,
+ placeholder: `Why should your ${punishment} be removed?`,
+ custom_id: 'appeal_why'
+ }
+ ]
+ }
+ ]
+ }
+ };
+
+ return respond(modal);
+ } else if (
+ interaction.data.custom_id.startsWith('appeal_accept;') ||
+ interaction.data.custom_id.startsWith('appeal_deny;')
+ ) {
+ const [action, punishment, guildId, userId, modlogCase] = interaction.data.custom_id.split(';') as [
+ 'appeal_accept' | 'appeal_deny',
+ PunishmentTypePresent,
+ Snowflake,
+ Snowflake,
+ string
+ ];
+
+ if (action === 'appeal_deny') {
+ await client.users
+ .send(userId, `Your ${punishment} appeal has been denied in ${client.guilds.resolve(guildId)!}.`)
+ .catch(() => {});
+
+ void respond({
+ type: InteractionResponseType.ChannelMessageWithSource,
+ data: {
+ components: [
+ {
+ type: 1,
+ components: [
+ {
+ type: ComponentType.Button,
+ style: ButtonStyle.Danger,
+ label: 'Close',
+ custom_id: 'appeal_denied'
+ }
+ ]
+ }
+ ]
+ }
+ });
+ }
+ }
+ } else if (interaction.type === InteractionType.ModalSubmit) {
+ if (interaction.data.custom_id.startsWith('appeal_submit;')) {
+ // eslint-disable-next-line @typescript-eslint/no-unused-vars
+ const [, punishment, guildId, userId, modlogCase] = interaction.data.custom_id.split(';') as [
+ 'appeal_submit',
+ PunishmentTypePresent,
+ Snowflake,
+ Snowflake,
+ string
+ ];
+
+ const guild = client.guilds.resolve(guildId);
+ if (!guild)
+ return respond({
+ type: InteractionResponseType.ChannelMessageWithSource,
+ data: {
+ content: `${util.emojis.error} I am no longer in that server.`
+ }
+ });
+
+ const channel = await guild.getLogChannel('appeals');
+ if (!channel)
+ return respond({
+ type: InteractionResponseType.ChannelMessageWithSource,
+ data: {
+ content: `${util.emojis.error} ${guild.name} has misconfigured their appeals channel.`
+ }
+ });
+
+ assert(interaction.user);
+ const user = new BushUser(client, interaction.user as any);
+ assert(user);
+
+ const caseId = await ModLog.findOne({ where: { user: userId, guild: guildId, id: modlogCase } });
+
+ const embed = new Embed()
+ .setTitle(`${util.capitalize(punishment)} Appeal`)
+ .setColor(util.colors.newBlurple)
+ .setTimestamp()
+ .setFooter({ text: `CaseID: ${modlogCase}` })
+ .setAuthor({ name: user.tag, iconURL: user.displayAvatarURL() })
+ .addField({
+ name: `Why were you ${Moderation.punishmentToPastTense(punishment)}?`,
+ value: interaction.data.components![0].components[0]!.value.substring(0, 1024)
+ })
+ .addField({
+ name: 'Do you believe it was fair?',
+ value: interaction.data.components![1].components[0]!.value.substring(0, 1024)
+ })
+ .addField({
+ name: `Why should your ${punishment} be removed?`,
+ value: interaction.data.components![2].components[0]!.value.substring(0, 1024)
+ })
+ .toJSON() as APIEmbed;
+
+ const components = [
+ new ActionRow({
+ type: 1,
+ components: [
+ // @ts-expect-error: outdated @discord.js/builders
+ new ButtonComponent({
+ type: 2,
+ custom_id: `appeal_accept;${punishment};${guildId};${userId};${modlogCase}`,
+ label: 'Accept',
+ style: 3 /* Success */
+ }).toJSON(),
+ // @ts-expect-error: outdated @discord.js/builders
+ new ButtonComponent({
+ type: 2,
+ custom_id: `appeal_deny;${punishment};${guildId};${userId};${modlogCase}`,
+ label: 'Deny',
+ style: 4 /* Danger */
+ }).toJSON()
+ ]
+ })
+ ];
+
+ await channel.send({ embeds: [embed], components });
+ } else {
+ return deferredMessageUpdate();
+ }
}
}
}
diff --git a/yarn.lock b/yarn.lock
index b0e784e..23c0b0d 100644
--- a/yarn.lock
+++ b/yarn.lock
@@ -15,61 +15,55 @@ __metadata:
linkType: hard
"@discordjs/builders@npm:^0.13.0-dev":
- version: 0.13.0-dev.1644408664.fe11ff5
- resolution: "@discordjs/builders@npm:0.13.0-dev.1644408664.fe11ff5"
+ version: 0.13.0-dev.1644753796.3ae6f3c
+ resolution: "@discordjs/builders@npm:0.13.0-dev.1644753796.3ae6f3c"
dependencies:
"@sindresorhus/is": ^4.4.0
discord-api-types: ^0.26.1
ts-mixer: ^6.0.0
tslib: ^2.3.1
zod: ^3.11.6
- checksum: ac70f545ffd87e3bc4f794e4bd759ec9dfdffd02bc46f8d06257166345c5cd18f28dd67c98e225c8882a9417f2b8c1abea1f44aeadb4432281eb733ac1e009e4
- languageName: node
- linkType: hard
-
-"@discordjs/collection@npm:^0.4.0":
- version: 0.4.0
- resolution: "@discordjs/collection@npm:0.4.0"
- checksum: fa8fc4246921f3230eb6c5d6d4dc0caf9dd659fcc903175944edf4fb0a9ed9913fdf164733d3f1e644ef469bc79b0d38a526ee620b92169cb40e79b40b0c716b
+ checksum: c9456389f7e0e0ccccaee0bc06924d6a92e47e941c334258b555c50c7d64cac72caafdbdbd913df62f107d21cd42d1f01f0dcbc75b9396a9ac3e3ea849cb501f
languageName: node
linkType: hard
"@discordjs/collection@npm:^0.6.0-dev":
- version: 0.6.0-dev.1644408625.fe11ff5
- resolution: "@discordjs/collection@npm:0.6.0-dev.1644408625.fe11ff5"
- checksum: 8035fc07ad1d7a302c8c70f3ee18db479dc51e07e9680f764af9039c8086001665722bb222fb5ebde633ca85690aac536403e03ad5dbd5cd7ffdc86690759cee
+ version: 0.6.0-dev.1644753793.3ae6f3c
+ resolution: "@discordjs/collection@npm:0.6.0-dev.1644753793.3ae6f3c"
+ checksum: 2ac348f3d5a0d9b3eb23e03db255b6de52a1dbdf8047061ff67adc83d7826a1c638de2d38007e20d87d76a7f1fb1a6050deed60ae9867916d1a66dc26a1cd1f8
languageName: node
linkType: hard
-"@discordjs/rest@npm:^0.3.0-dev":
- version: 0.3.0
- resolution: "@discordjs/rest@npm:0.3.0"
+"@discordjs/rest@npm:^0.4.0-dev":
+ version: 0.4.0-dev.1644753853.3ae6f3c
+ resolution: "@discordjs/rest@npm:0.4.0-dev.1644753853.3ae6f3c"
dependencies:
- "@discordjs/collection": ^0.4.0
- "@sapphire/async-queue": ^1.1.9
- "@sapphire/snowflake": ^3.0.1
+ "@discordjs/collection": ^0.6.0-dev
+ "@sapphire/async-queue": ^1.2.0
+ "@sapphire/snowflake": ^3.1.0
+ "@types/node-fetch": ^2.5.12
discord-api-types: ^0.26.1
form-data: ^4.0.0
- node-fetch: ^2.6.5
+ node-fetch: ^2.6.7
tslib: ^2.3.1
- checksum: 0e5724156e0375b2181036d25d8847c5b7d8ab46a3409a19dad57ec9b3301d9127917a52558d3daa7e2b513804d4de9fcd5f6d56e056cc48dd567ebf26548c6d
+ checksum: 6871129ea94619e2f97282cad23fc3dd70580869cdbc4e76d773fc2d9e06944dc31580dc6f46bfccf4bb0b9bde844a68900c82222526b088181900eeffcf22fa
languageName: node
linkType: hard
-"@eslint/eslintrc@npm:^1.0.5":
- version: 1.0.5
- resolution: "@eslint/eslintrc@npm:1.0.5"
+"@eslint/eslintrc@npm:^1.1.0":
+ version: 1.1.0
+ resolution: "@eslint/eslintrc@npm:1.1.0"
dependencies:
ajv: ^6.12.4
debug: ^4.3.2
- espree: ^9.2.0
+ espree: ^9.3.1
globals: ^13.9.0
ignore: ^4.0.6
import-fresh: ^3.2.1
js-yaml: ^4.1.0
minimatch: ^3.0.4
strip-json-comments: ^3.1.1
- checksum: b35b50d7b65bd8acd92a05b6fb15ac62c0cefa40dfef0324ca5bf8632bf3679bab6e173c53b3ad1e1d837701cecdbd9c144b35f46588cdf4e046a9caa272488d
+ checksum: 784aa2157e2808b52bbbaf1d1cfca9a6ba0b2faaa3696eb7a1229d4b357400fbd8a6aa09a16e7ae0868ea075d3a8f365cf5928b6d05a1df47f40a1167423a4fa
languageName: node
linkType: hard
@@ -199,111 +193,111 @@ __metadata:
languageName: node
linkType: hard
-"@sapphire/async-queue@npm:^1.1.9":
+"@sapphire/async-queue@npm:^1.2.0":
version: 1.2.0
resolution: "@sapphire/async-queue@npm:1.2.0"
checksum: 9959c91fe031e9350134740b68e64798eff1f72f1417f312a4f7bebbd875035a406ba5ae1e71640c3819dec10d0f86a0588b494088f353f85701f2f1196e4560
languageName: node
linkType: hard
-"@sapphire/snowflake@npm:^3.0.1, @sapphire/snowflake@npm:^3.1.0":
+"@sapphire/snowflake@npm:^3.1.0":
version: 3.1.0
resolution: "@sapphire/snowflake@npm:3.1.0"
checksum: 979d41f531983b992e65f79a75016e92bb4f3984148bd7e2164059b4e8e18df0206c36c5a1a02f32c39c425b268f2e7871d9eef1eb5f1690f8837e451cc00812
languageName: node
linkType: hard
-"@sentry/core@npm:6.17.6":
- version: 6.17.6
- resolution: "@sentry/core@npm:6.17.6"
+"@sentry/core@npm:6.17.7":
+ version: 6.17.7
+ resolution: "@sentry/core@npm:6.17.7"
dependencies:
- "@sentry/hub": 6.17.6
- "@sentry/minimal": 6.17.6
- "@sentry/types": 6.17.6
- "@sentry/utils": 6.17.6
+ "@sentry/hub": 6.17.7
+ "@sentry/minimal": 6.17.7
+ "@sentry/types": 6.17.7
+ "@sentry/utils": 6.17.7
tslib: ^1.9.3
- checksum: 66909a0db7301553581e85fb3df2e4b1b2050dc19e24d806d4551c1b5eed14ffa95462053d8e0e3f81ad32da0871b94945abad9f44ad9d5a178ecbf4ced3b326
+ checksum: c42cf0046b0c33131d31acfa73121ff0774c4e447dd47f4e989d0a083355280175ead99a5cc121813078bc06d22d9bfa19bba046b66e5bae9670b7d86cd68732
languageName: node
linkType: hard
-"@sentry/hub@npm:6.17.6":
- version: 6.17.6
- resolution: "@sentry/hub@npm:6.17.6"
+"@sentry/hub@npm:6.17.7":
+ version: 6.17.7
+ resolution: "@sentry/hub@npm:6.17.7"
dependencies:
- "@sentry/types": 6.17.6
- "@sentry/utils": 6.17.6
+ "@sentry/types": 6.17.7
+ "@sentry/utils": 6.17.7
tslib: ^1.9.3
- checksum: 6446505332a3d2fc07e50f456dcf8782a0c457da75df30e426bbe1f3a39b309232560074b18bc2b0cd355bec4d3be5eb99f013ef9379aadead9373dd06a02f80
+ checksum: 9b18cfe9f54eac2fe8e04fbfc4ed3388b875d3b486c60ec3bcd9558673dc83a070abaaea2f1810c92a863f20c629f7e38bce55a33fa7f4c30c6f63c1274add15
languageName: node
linkType: hard
-"@sentry/integrations@npm:^6.17.6":
- version: 6.17.6
- resolution: "@sentry/integrations@npm:6.17.6"
+"@sentry/integrations@npm:^6.17.7":
+ version: 6.17.7
+ resolution: "@sentry/integrations@npm:6.17.7"
dependencies:
- "@sentry/types": 6.17.6
- "@sentry/utils": 6.17.6
+ "@sentry/types": 6.17.7
+ "@sentry/utils": 6.17.7
localforage: ^1.8.1
tslib: ^1.9.3
- checksum: 1b64ed2038b08b305a37aece683d25f7c3ff93b7508c630be50b3416252c701bcd93f4e9ae4310e57e2db442602947a9ee72eb26067e1875da35dacde61e9884
+ checksum: e77b18c869cd812615806956134ee16bbcd6cc25dc5f1b939fdf2071c93fe8bd567cf4ec8fdefb5c6b6b58cfebbcd99e6cf5bde1b546b353e83a520d6e83e1a2
languageName: node
linkType: hard
-"@sentry/minimal@npm:6.17.6":
- version: 6.17.6
- resolution: "@sentry/minimal@npm:6.17.6"
+"@sentry/minimal@npm:6.17.7":
+ version: 6.17.7
+ resolution: "@sentry/minimal@npm:6.17.7"
dependencies:
- "@sentry/hub": 6.17.6
- "@sentry/types": 6.17.6
+ "@sentry/hub": 6.17.7
+ "@sentry/types": 6.17.7
tslib: ^1.9.3
- checksum: c721f5306369569af43a0dbe4d612e8ff7b0fb228b01313060bd207276b3f2302c3227fd776db2b0920fcec8ab7ed308545c4bb2e1b5d54ee2a70addb6232f22
+ checksum: 2dfbc9ee02b9e2b53e1fabdb84a1ea2cb8ce69c89b1b69e023a2c1940f1365d502be0caec1e744f46ea287f8466c9d9c190ee91f98332e15d1b35680a9b2c55a
languageName: node
linkType: hard
-"@sentry/node@npm:^6.17.6":
- version: 6.17.6
- resolution: "@sentry/node@npm:6.17.6"
+"@sentry/node@npm:^6.17.7":
+ version: 6.17.7
+ resolution: "@sentry/node@npm:6.17.7"
dependencies:
- "@sentry/core": 6.17.6
- "@sentry/hub": 6.17.6
- "@sentry/tracing": 6.17.6
- "@sentry/types": 6.17.6
- "@sentry/utils": 6.17.6
+ "@sentry/core": 6.17.7
+ "@sentry/hub": 6.17.7
+ "@sentry/tracing": 6.17.7
+ "@sentry/types": 6.17.7
+ "@sentry/utils": 6.17.7
cookie: ^0.4.1
https-proxy-agent: ^5.0.0
lru_map: ^0.3.3
tslib: ^1.9.3
- checksum: 2d66c5797605fc1a3c76da775565dee49dcbbfb874eeeb98c1d3b624dc8861ae880204b63dba5cda274b62af4d3d0169180eeb139a4ed5a108ee3e137f656d2a
+ checksum: 0a80fac448f815c8e4b6e487ec226ea83bcde8972a8b83af7cbf679cd5655123d0e4e5c50c09274a569d61032156964cb1f7b59b3e406914430c0130afea61f4
languageName: node
linkType: hard
-"@sentry/tracing@npm:6.17.6, @sentry/tracing@npm:^6.17.6":
- version: 6.17.6
- resolution: "@sentry/tracing@npm:6.17.6"
+"@sentry/tracing@npm:6.17.7, @sentry/tracing@npm:^6.17.7":
+ version: 6.17.7
+ resolution: "@sentry/tracing@npm:6.17.7"
dependencies:
- "@sentry/hub": 6.17.6
- "@sentry/minimal": 6.17.6
- "@sentry/types": 6.17.6
- "@sentry/utils": 6.17.6
+ "@sentry/hub": 6.17.7
+ "@sentry/minimal": 6.17.7
+ "@sentry/types": 6.17.7
+ "@sentry/utils": 6.17.7
tslib: ^1.9.3
- checksum: 2f46a6f2a79152efc2639dc50e6df1c9b29db4f9bc7eaaae5251be7b998ecb7685fe003644b7b250637cdd8a3a30ab1dfe78687661ec726a1cb8016aafb0a154
+ checksum: 76f8540a331ba0180df42501deb2a4fad8ac4b5a7c469f53a0ef25d6227c765fc991bad5c28c1bfc694b9f17d6a5cf0854b3c6a4ced0f2147e2196af8a266b34
languageName: node
linkType: hard
-"@sentry/types@npm:6.17.6, @sentry/types@npm:^6.17.6":
- version: 6.17.6
- resolution: "@sentry/types@npm:6.17.6"
- checksum: c8b080202271f5cbacc91e070f6d02ce4fd87089e7ad038036b1b03b46340ed9e5edbea4ce47738107c547fd6aabd687ca376419dcb2343faad8a5f7b7de4873
+"@sentry/types@npm:6.17.7, @sentry/types@npm:^6.17.7":
+ version: 6.17.7
+ resolution: "@sentry/types@npm:6.17.7"
+ checksum: 6e6bc8c46e78f921e0c85e46946349fb7347ef0af83c0cf3086ab022b15d003780acd02f4f29beb2aefdde3b9a512bd4f31d47f0bea4cee60eab60c117a733d9
languageName: node
linkType: hard
-"@sentry/utils@npm:6.17.6":
- version: 6.17.6
- resolution: "@sentry/utils@npm:6.17.6"
+"@sentry/utils@npm:6.17.7":
+ version: 6.17.7
+ resolution: "@sentry/utils@npm:6.17.7"
dependencies:
- "@sentry/types": 6.17.6
+ "@sentry/types": 6.17.7
tslib: ^1.9.3
- checksum: b57ce769e41b98d93ba5ed719998b93fd93a52c9dd7465b19d44c82d2a0974e72eea417e1b97ca471cd6a81474e28aaf62eee8712d5adfb2b93f10c8ba881799
+ checksum: dd41419a232ae7547bbe9bd66297b197c1f6daab780e12919adcb3bb09d1c631d269ed8a65cac3a070bb8ca646006b062a5de16104fcb5a7de465238c90d04f2
languageName: node
linkType: hard
@@ -478,6 +472,16 @@ __metadata:
languageName: node
linkType: hard
+"@types/node-fetch@npm:^2.5.12":
+ version: 2.5.12
+ resolution: "@types/node-fetch@npm:2.5.12"
+ dependencies:
+ "@types/node": "*"
+ form-data: ^3.0.0
+ checksum: ad63c85ba6a9477b8e057ec8682257738130d98e8ece4e31141789bd99df9d9147985cc8bc0cb5c8983ed5aa6bb95d46df23d1e055f4ad5cf8b82fc69cf626c7
+ languageName: node
+ linkType: hard
+
"@types/node-os-utils@npm:^1.2.0":
version: 1.2.0
resolution: "@types/node-os-utils@npm:1.2.0"
@@ -916,10 +920,10 @@ __metadata:
"@notenoughupdates/simplify-number": ^1.0.1
"@notenoughupdates/wolfram-alpha-api": ^1.0.1
"@sapphire/snowflake": ^3.1.0
- "@sentry/integrations": ^6.17.6
- "@sentry/node": ^6.17.6
- "@sentry/tracing": ^6.17.6
- "@sentry/types": ^6.17.6
+ "@sentry/integrations": ^6.17.7
+ "@sentry/node": ^6.17.7
+ "@sentry/tracing": ^6.17.7
+ "@sentry/types": ^6.17.7
"@types/eslint": ^8.4.1
"@types/express": ^4.17.13
"@types/lodash": ^4.14.178
@@ -937,13 +941,13 @@ __metadata:
chalk: ^5.0.0
deep-lock: ^1.0.0
discord-akairo: "npm:@notenoughupdates/discord-akairo@dev"
- discord-api-types: 0.26.1
+ discord-api-types: 0.27.0
+ discord-api-types-next: "npm:discord-api-types@next"
discord.js: "npm:@notenoughupdates/discord.js@dev"
- eslint: ^8.8.0
+ eslint: ^8.9.0
eslint-config-prettier: ^8.3.0
eslint-plugin-deprecation: ^1.3.2
eslint-plugin-import: ^2.25.4
- eslint-plugin-node: ^11.1.0
fuse.js: ^6.5.3
got: ^12.0.1
lodash: ^4.17.21
@@ -955,7 +959,7 @@ __metadata:
pg: ^8.7.3
pg-hstore: ^2.3.4
prettier: ^2.5.1
- pretty-bytes: ^5.6.0
+ pretty-bytes: ^6.0.0
rimraf: ^3.0.2
sequelize: 6.16.1
tinycolor2: ^1.4.2
@@ -1286,13 +1290,27 @@ __metadata:
linkType: hard
"discord-akairo@npm:@notenoughupdates/discord-akairo@dev":
- version: 9.0.10-dev.1644108723.7814d7c
- resolution: "@notenoughupdates/discord-akairo@npm:9.0.10-dev.1644108723.7814d7c"
- checksum: a55770b6f1dec4edd3bc2771cb896aeb12b329d6ed9b007c3fc111430665a1e84fb46d64e0cc8682d4092e9c70d3cf28cfdc77d6a171fda3d8d5cfce7edbfdf5
+ version: 9.1.2-dev.1644723718.99887ac
+ resolution: "@notenoughupdates/discord-akairo@npm:9.1.2-dev.1644723718.99887ac"
+ checksum: 9a6abf342d4abadcf8ee6af3e20235399bcac215ad58d4cbacd6a6f39dbfd32e8601574a1561cb5b538e82ac05f47864cf8c4d2a3586505f47284a45efcb49c8
languageName: node
linkType: hard
-"discord-api-types@npm:0.26.1, discord-api-types@npm:^0.26.1":
+"discord-api-types-next@npm:discord-api-types@next":
+ version: 0.28.0-next.ed1f717.1644755287
+ resolution: "discord-api-types@npm:0.28.0-next.ed1f717.1644755287"
+ checksum: d33ee0264a6e3669951b9c3f157c7010802736dbd142937258dc34bf27bd71a98667c96fb65d61603429c606d5a19a9c017bdf74dfa4988ea9a2841a99b1dde0
+ languageName: node
+ linkType: hard
+
+"discord-api-types@npm:0.27.0, discord-api-types@npm:^0.27.0":
+ version: 0.27.0
+ resolution: "discord-api-types@npm:0.27.0"
+ checksum: 5a74a49ad7e57ea24e67d431de30cc7056d6d422b607c7d5a7dd35c683c8b87d70ec35a0d3929971adb411acc3df2bd6a77c1401ce30b29690bd1305e427265c
+ languageName: node
+ linkType: hard
+
+"discord-api-types@npm:^0.26.1":
version: 0.26.1
resolution: "discord-api-types@npm:0.26.1"
checksum: e53bfa7589b24108e6b403dbe213da34c4592f72e2b8fde6800dcb6c703065887ecbd644e1cdf694e4c7796954bc51462ced868f26ec45dc1e0dc4fa8d3c723c
@@ -1300,18 +1318,18 @@ __metadata:
linkType: hard
"discord.js@npm:@notenoughupdates/discord.js@dev":
- version: 14.0.0-dev.1644471352.7179c1b
- resolution: "@notenoughupdates/discord.js@npm:14.0.0-dev.1644471352.7179c1b"
+ version: 14.0.0-dev.1644769585.0143bcc
+ resolution: "@notenoughupdates/discord.js@npm:14.0.0-dev.1644769585.0143bcc"
dependencies:
"@discordjs/builders": ^0.13.0-dev
"@discordjs/collection": ^0.6.0-dev
- "@discordjs/rest": ^0.3.0-dev
+ "@discordjs/rest": ^0.4.0-dev
"@sapphire/snowflake": ^3.1.0
"@types/ws": ^8.2.2
- discord-api-types: ^0.26.1
+ discord-api-types: ^0.27.0
node-fetch: ^2.6.7
- ws: ^8.4.2
- checksum: 222e8a3f1389ce50bc4489abf3dcee99b9eb058888f00d0fb32247263215598c9c94ae6c58f48c6e8498ec854e90838c95d2edeb51101af89d705ce2dfbeeb81
+ ws: ^8.5.0
+ checksum: 653276988184559a57ed5d07ae5955cd04300fa9245aa5820a9adb39aa538e3efc5f28174d09b8f255ff8d9d018c5cb404c6c3bd87d217fcdf7ef7bd316860b8
languageName: node
linkType: hard
@@ -1477,18 +1495,6 @@ __metadata:
languageName: node
linkType: hard
-"eslint-plugin-es@npm:^3.0.0":
- version: 3.0.1
- resolution: "eslint-plugin-es@npm:3.0.1"
- dependencies:
- eslint-utils: ^2.0.0
- regexpp: ^3.0.0
- peerDependencies:
- eslint: ">=4.19.1"
- checksum: e57592c52301ee8ddc296ae44216df007f3a870bcb3be8d1fbdb909a1d3a3efe3fa3785de02066f9eba1d6466b722d3eb3cc3f8b75b3cf6a1cbded31ac6298e4
- languageName: node
- linkType: hard
-
"eslint-plugin-import@npm:^2.25.4":
version: 2.25.4
resolution: "eslint-plugin-import@npm:2.25.4"
@@ -1512,22 +1518,6 @@ __metadata:
languageName: node
linkType: hard
-"eslint-plugin-node@npm:^11.1.0":
- version: 11.1.0
- resolution: "eslint-plugin-node@npm:11.1.0"
- dependencies:
- eslint-plugin-es: ^3.0.0
- eslint-utils: ^2.0.0
- ignore: ^5.1.1
- minimatch: ^3.0.4
- resolve: ^1.10.1
- semver: ^6.1.0
- peerDependencies:
- eslint: ">=5.16.0"
- checksum: 5804c4f8a6e721f183ef31d46fbe3b4e1265832f352810060e0502aeac7de034df83352fc88643b19641bb2163f2587f1bd4119aff0fd21e8d98c57c450e013b
- languageName: node
- linkType: hard
-
"eslint-scope@npm:^5.1.1":
version: 5.1.1
resolution: "eslint-scope@npm:5.1.1"
@@ -1538,22 +1528,13 @@ __metadata:
languageName: node
linkType: hard
-"eslint-scope@npm:^7.1.0":
- version: 7.1.0
- resolution: "eslint-scope@npm:7.1.0"
+"eslint-scope@npm:^7.1.1":
+ version: 7.1.1
+ resolution: "eslint-scope@npm:7.1.1"
dependencies:
esrecurse: ^4.3.0
estraverse: ^5.2.0
- checksum: 2070470a0725438ed47075b2574a4c03cf59aa32648da8cff9e3548c84f6b0079cfdb9ee1dd7ab0bfe97011f64b2af5bfd4b69cf14a1292130dec661eec7914a
- languageName: node
- linkType: hard
-
-"eslint-utils@npm:^2.0.0":
- version: 2.1.0
- resolution: "eslint-utils@npm:2.1.0"
- dependencies:
- eslint-visitor-keys: ^1.1.0
- checksum: 27500938f348da42100d9e6ad03ae29b3de19ba757ae1a7f4a087bdcf83ac60949bbb54286492ca61fac1f5f3ac8692dd21537ce6214240bf95ad0122f24d71d
+ checksum: 9f6e974ab2db641ca8ab13508c405b7b859e72afe9f254e8131ff154d2f40c99ad4545ce326fd9fde3212ff29707102562a4834f1c48617b35d98c71a97fbf3e
languageName: node
linkType: hard
@@ -1568,13 +1549,6 @@ __metadata:
languageName: node
linkType: hard
-"eslint-visitor-keys@npm:^1.1.0":
- version: 1.3.0
- resolution: "eslint-visitor-keys@npm:1.3.0"
- checksum: 37a19b712f42f4c9027e8ba98c2b06031c17e0c0a4c696cd429bd9ee04eb43889c446f2cd545e1ff51bef9593fcec94ecd2c2ef89129fcbbf3adadbef520376a
- languageName: node
- linkType: hard
-
"eslint-visitor-keys@npm:^2.0.0":
version: 2.1.0
resolution: "eslint-visitor-keys@npm:2.1.0"
@@ -1582,18 +1556,18 @@ __metadata:
languageName: node
linkType: hard
-"eslint-visitor-keys@npm:^3.0.0, eslint-visitor-keys@npm:^3.1.0, eslint-visitor-keys@npm:^3.2.0":
- version: 3.2.0
- resolution: "eslint-visitor-keys@npm:3.2.0"
- checksum: fdadbb26f9e6417d3db7ad4f00bb0d573b6031c32fa72e8cdae32d038223faaeddff2ee443c90cb489bf774e75bff765c00912b8f9106d65e4f202ccd78c1b18
+"eslint-visitor-keys@npm:^3.0.0, eslint-visitor-keys@npm:^3.3.0":
+ version: 3.3.0
+ resolution: "eslint-visitor-keys@npm:3.3.0"
+ checksum: d59e68a7c5a6d0146526b0eec16ce87fbf97fe46b8281e0d41384224375c4e52f5ffb9e16d48f4ea50785cde93f766b0c898e31ab89978d88b0e1720fbfb7808
languageName: node
linkType: hard
-"eslint@npm:^8.8.0":
- version: 8.8.0
- resolution: "eslint@npm:8.8.0"
+"eslint@npm:^8.9.0":
+ version: 8.9.0
+ resolution: "eslint@npm:8.9.0"
dependencies:
- "@eslint/eslintrc": ^1.0.5
+ "@eslint/eslintrc": ^1.1.0
"@humanwhocodes/config-array": ^0.9.2
ajv: ^6.10.0
chalk: ^4.0.0
@@ -1601,10 +1575,10 @@ __metadata:
debug: ^4.3.2
doctrine: ^3.0.0
escape-string-regexp: ^4.0.0
- eslint-scope: ^7.1.0
+ eslint-scope: ^7.1.1
eslint-utils: ^3.0.0
- eslint-visitor-keys: ^3.2.0
- espree: ^9.3.0
+ eslint-visitor-keys: ^3.3.0
+ espree: ^9.3.1
esquery: ^1.4.0
esutils: ^2.0.2
fast-deep-equal: ^3.1.3
@@ -1630,18 +1604,18 @@ __metadata:
v8-compile-cache: ^2.0.3
bin:
eslint: bin/eslint.js
- checksum: 41a7e85bf84cf9f2d758ef3e8d08020a39a2836703728b59535684681349bd021c2c6e24174462b844a914870d707d2151e0371198899d957b444de91adaa435
+ checksum: 8efecdb9752ee6cb4d2787a14e00cbeab29562ed95dd71c6f3f8ac410426a067d5aa659416d2290e46ca44bc5607e6a6e6c62f814694d8639f80666f522022a7
languageName: node
linkType: hard
-"espree@npm:^9.2.0, espree@npm:^9.3.0":
- version: 9.3.0
- resolution: "espree@npm:9.3.0"
+"espree@npm:^9.3.1":
+ version: 9.3.1
+ resolution: "espree@npm:9.3.1"
dependencies:
acorn: ^8.7.0
acorn-jsx: ^5.3.1
- eslint-visitor-keys: ^3.1.0
- checksum: c0f1885c4eab652f9be08eb9228cea0df046b559b29d4aed8d6590ea9bd60177d4cb245d204a6f737a79a096861bb4ab8e480aeb8c1dbafef5beec1157353ce4
+ eslint-visitor-keys: ^3.3.0
+ checksum: d7161db30b65427e0799383699ac4c441533a38faee005153694b68b933ba7a24666680edfc490fa77e3a84a22dbd955768034a6f811af5049774eead83063a5
languageName: node
linkType: hard
@@ -1788,6 +1762,17 @@ __metadata:
languageName: node
linkType: hard
+"form-data@npm:^3.0.0":
+ version: 3.0.1
+ resolution: "form-data@npm:3.0.1"
+ dependencies:
+ asynckit: ^0.4.0
+ combined-stream: ^1.0.8
+ mime-types: ^2.1.12
+ checksum: b019e8d35c8afc14a2bd8a7a92fa4f525a4726b6d5a9740e8d2623c30e308fbb58dc8469f90415a856698933c8479b01646a9dff33c87cc4e76d72aedbbf860d
+ languageName: node
+ linkType: hard
+
"form-data@npm:^4.0.0":
version: 4.0.0
resolution: "form-data@npm:4.0.0"
@@ -2115,7 +2100,7 @@ __metadata:
languageName: node
linkType: hard
-"ignore@npm:^5.1.1, ignore@npm:^5.1.8, ignore@npm:^5.2.0":
+"ignore@npm:^5.1.8, ignore@npm:^5.2.0":
version: 5.2.0
resolution: "ignore@npm:5.2.0"
checksum: 6b1f926792d614f64c6c83da3a1f9c83f6196c2839aa41e1e32dd7b8d174cef2e329d75caabb62cb61ce9dc432f75e67d07d122a037312db7caa73166a1bdb77
@@ -2598,11 +2583,11 @@ __metadata:
linkType: hard
"minimatch@npm:^3.0.4":
- version: 3.0.5
- resolution: "minimatch@npm:3.0.5"
+ version: 3.1.1
+ resolution: "minimatch@npm:3.1.1"
dependencies:
brace-expansion: ^1.1.7
- checksum: a3b84b426eafca947741b864502cee02860c4e7b145de11ad98775cfcf3066fef422583bc0ffce0952ddf4750c1ccf4220b1556430d4ce10139f66247d87d69e
+ checksum: e9e3772e4ea06ea3a888d39bc7690d3c812ee7e5a70c2d2f568ccadac0249a027f865589d19ad03ed937e6ca3b4ad35f85411db9670f7877d8fc2ed452f1cd37
languageName: node
linkType: hard
@@ -3162,10 +3147,10 @@ __metadata:
languageName: node
linkType: hard
-"pretty-bytes@npm:^5.6.0":
- version: 5.6.0
- resolution: "pretty-bytes@npm:5.6.0"
- checksum: 9c082500d1e93434b5b291bd651662936b8bd6204ec9fa17d563116a192d6d86b98f6d328526b4e8d783c07d5499e2614a807520249692da9ec81564b2f439cd
+"pretty-bytes@npm:^6.0.0":
+ version: 6.0.0
+ resolution: "pretty-bytes@npm:6.0.0"
+ checksum: 0bb9f95e617236404b29a8392c6efd82d65805f622f5e809ecd70068102be857d4e3276c86d2a32fa2ef851cc29472e380945dab7bec83ec79bd57a19a10faf7
languageName: node
linkType: hard
@@ -3235,7 +3220,7 @@ __metadata:
languageName: node
linkType: hard
-"regexpp@npm:^3.0.0, regexpp@npm:^3.2.0":
+"regexpp@npm:^3.2.0":
version: 3.2.0
resolution: "regexpp@npm:3.2.0"
checksum: a78dc5c7158ad9ddcfe01aa9144f46e192ddbfa7b263895a70a5c6c73edd9ce85faf7c0430e59ac38839e1734e275b9c3de5c57ee3ab6edc0e0b1bdebefccef8
@@ -3256,7 +3241,7 @@ __metadata:
languageName: node
linkType: hard
-"resolve@npm:^1.10.1, resolve@npm:^1.20.0":
+"resolve@npm:^1.20.0":
version: 1.22.0
resolution: "resolve@npm:1.22.0"
dependencies:
@@ -3269,7 +3254,7 @@ __metadata:
languageName: node
linkType: hard
-"resolve@patch:resolve@^1.10.1#~builtin<compat/resolve>, resolve@patch:resolve@^1.20.0#~builtin<compat/resolve>":
+"resolve@patch:resolve@^1.20.0#~builtin<compat/resolve>":
version: 1.22.0
resolution: "resolve@patch:resolve@npm%3A1.22.0#~builtin<compat/resolve>::version=1.22.0&hash=07638b"
dependencies:
@@ -3353,7 +3338,7 @@ __metadata:
languageName: node
linkType: hard
-"semver@npm:^6.0.0, semver@npm:^6.1.0":
+"semver@npm:^6.0.0":
version: 6.3.0
resolution: "semver@npm:6.3.0"
bin:
@@ -3922,7 +3907,7 @@ __metadata:
languageName: node
linkType: hard
-"ws@npm:^8.4.2":
+"ws@npm:^8.5.0":
version: 8.5.0
resolution: "ws@npm:8.5.0"
peerDependencies: