aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorIRONM00N <64110067+IRONM00N@users.noreply.github.com>2022-10-03 22:57:40 -0400
committerIRONM00N <64110067+IRONM00N@users.noreply.github.com>2022-10-03 22:57:40 -0400
commit612ed820a0600ec11ed642005377cd7f5a8a8b77 (patch)
tree6bca4e7268fd0063ff53cf64fa44df62a23dba50
parented98ff7e2679f362f2657e77a6cf8dd3ce9b3d43 (diff)
downloadtanzanite-612ed820a0600ec11ed642005377cd7f5a8a8b77.tar.gz
tanzanite-612ed820a0600ec11ed642005377cd7f5a8a8b77.tar.bz2
tanzanite-612ed820a0600ec11ed642005377cd7f5a8a8b77.zip
wip
-rw-r--r--.yarnrc.yml2
-rw-r--r--lib/automod/AutomodShared.ts4
-rw-r--r--lib/common/Appeals.ts273
-rw-r--r--lib/common/ButtonPaginator.ts6
-rw-r--r--lib/common/ConfirmationPrompt.ts12
-rw-r--r--lib/common/DeleteButton.ts8
-rw-r--r--lib/common/HighlightManager.ts3
-rw-r--r--lib/common/Moderation.ts668
-rw-r--r--lib/common/tags.ts132
-rw-r--r--lib/extensions/discord-akairo/BotCommand.ts33
-rw-r--r--lib/extensions/discord-akairo/BotCommandHandler.ts11
-rw-r--r--lib/extensions/discord-akairo/BotInhibitor.ts6
-rw-r--r--lib/extensions/discord-akairo/BotInhibitorHandler.ts7
-rw-r--r--lib/extensions/discord-akairo/BotListener.ts5
-rw-r--r--lib/extensions/discord-akairo/BotListenerHandler.ts2
-rw-r--r--lib/extensions/discord-akairo/BotTask.ts2
-rw-r--r--lib/extensions/discord-akairo/BotTaskHandler.ts2
-rw-r--r--lib/extensions/discord-akairo/SlashMessage.ts2
-rw-r--r--lib/extensions/discord-akairo/TanzaniteClient.ts48
-rw-r--r--lib/extensions/discord.js/BotClientEvents.ts2
-rw-r--r--lib/extensions/discord.js/ExtendedGuild.ts40
-rw-r--r--lib/extensions/discord.js/ExtendedGuildMember.ts48
-rw-r--r--lib/extensions/discord.js/ExtendedMessage.ts8
-rw-r--r--lib/extensions/discord.js/ExtendedUser.ts2
-rw-r--r--lib/global.ts4
-rw-r--r--lib/index.ts4
-rw-r--r--lib/models/instance/ActivePunishment.ts8
-rw-r--r--lib/models/instance/Guild.ts10
-rw-r--r--lib/models/instance/Level.ts3
-rw-r--r--lib/models/instance/ModLog.ts123
-rw-r--r--lib/types/misc.ts8
-rw-r--r--lib/utils/Arg.ts2
-rw-r--r--lib/utils/BotClientUtils.ts5
-rw-r--r--lib/utils/Constants.ts3
-rw-r--r--lib/utils/ErrorHandler.ts2
-rw-r--r--lib/utils/Utils.ts16
m---------neu-item-repo0
m---------neu-item-repo-dangerous0
-rw-r--r--package.json77
-rw-r--r--src/bot.ts28
-rw-r--r--src/commands/config/config.ts17
-rw-r--r--src/commands/config/disable.ts4
-rw-r--r--src/commands/config/log.ts10
-rw-r--r--src/commands/dev/eval.ts2
-rw-r--r--src/commands/dev/superUser.ts2
-rw-r--r--src/commands/dev/test.ts156
-rw-r--r--src/commands/fun/minesweeper.ts4
-rw-r--r--src/commands/info/guildInfo.ts111
-rw-r--r--src/commands/info/help.ts4
-rw-r--r--src/commands/info/inviteInfo.ts7
-rw-r--r--src/commands/info/ping.ts2
-rw-r--r--src/commands/info/snowflake.ts48
-rw-r--r--src/commands/info/userInfo.ts112
-rw-r--r--src/commands/leveling/level.ts8
-rw-r--r--src/commands/leveling/setLevel.ts28
-rw-r--r--src/commands/leveling/setXp.ts34
-rw-r--r--src/commands/moderation/ban.ts4
-rw-r--r--src/commands/moderation/block.ts2
-rw-r--r--src/commands/moderation/evidence.ts2
-rw-r--r--src/commands/moderation/kick.ts2
-rw-r--r--src/commands/moderation/modlog.ts60
-rw-r--r--src/commands/moderation/mute.ts2
-rw-r--r--src/commands/moderation/myLogs.ts12
-rw-r--r--src/commands/moderation/role.ts2
-rw-r--r--src/commands/moderation/slowmode.ts6
-rw-r--r--src/commands/moderation/timeout.ts8
-rw-r--r--src/commands/moderation/unblock.ts8
-rw-r--r--src/commands/moderation/unmute.ts8
-rw-r--r--src/commands/moderation/untimeout.ts8
-rw-r--r--src/commands/moderation/warn.ts2
-rw-r--r--src/commands/moulberry-bush/capes.ts6
-rw-r--r--src/commands/tickets/ticket-!.ts2
-rw-r--r--src/commands/utilities/activity.ts2
-rw-r--r--src/commands/utilities/highlight-!.ts2
-rw-r--r--src/commands/utilities/highlight-block.ts2
-rw-r--r--src/commands/utilities/highlight-matches.ts2
-rw-r--r--src/commands/utilities/highlight-unblock.ts2
-rw-r--r--src/commands/utilities/price.ts4
-rw-r--r--src/commands/utilities/steal.ts8
-rw-r--r--src/commands/utilities/whoHasRole.ts2
-rw-r--r--src/commands/utilities/wolframAlpha.ts6
-rw-r--r--src/context-menu-commands/message/viewRaw.ts2
-rw-r--r--src/context-menu-commands/user/modlog.ts9
-rw-r--r--src/context-menu-commands/user/userInfo.ts28
-rw-r--r--src/listeners/bush/appealListener.ts14
-rw-r--r--src/listeners/bush/experimentYoink.ts28
-rw-r--r--src/listeners/client/ready.ts28
-rw-r--r--src/listeners/commands/commandBlocked.ts4
-rw-r--r--src/listeners/contextCommands/contextCommandBlocked.ts4
-rw-r--r--src/listeners/contextCommands/contextCommandError.ts2
-rw-r--r--src/listeners/contextCommands/contextCommandNotFound.ts2
-rw-r--r--src/listeners/contextCommands/contextCommandStarted.ts2
-rw-r--r--src/listeners/guild/syncUnbanPunishmentModel.ts2
-rw-r--r--src/listeners/interaction/$interactionCreate.ts31
-rw-r--r--src/listeners/interaction/button.ts129
-rw-r--r--src/listeners/interaction/interactionCreate.ts78
-rw-r--r--src/listeners/interaction/modalSubmit.ts20
-rw-r--r--src/listeners/interaction/selectMenu.ts23
-rw-r--r--src/listeners/member-custom/levelUpdate.ts3
-rw-r--r--src/listeners/message/autoPublisher.ts5
-rw-r--r--src/listeners/message/level.ts57
-rw-r--r--src/listeners/message/quoteCreate.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.ts236
-rw-r--r--src/tasks/feature/removeExpiredPunishements.ts8
-rw-r--r--yarn.lock1582
109 files changed, 2408 insertions, 2231 deletions
diff --git a/.yarnrc.yml b/.yarnrc.yml
index bd5ccfd..33ad4a3 100644
--- a/.yarnrc.yml
+++ b/.yarnrc.yml
@@ -2,7 +2,7 @@ enableGlobalCache: true
enableTelemetry: false
-nodeLinker: pnpm
+nodeLinker: node-modules
plugins:
- path: .yarn/plugins/@yarnpkg/plugin-interactive-tools.cjs
diff --git a/lib/automod/AutomodShared.ts b/lib/automod/AutomodShared.ts
index 29b0536..48217dd 100644
--- a/lib/automod/AutomodShared.ts
+++ b/lib/automod/AutomodShared.ts
@@ -162,7 +162,7 @@ export async function handleAutomodInteraction(interaction: ButtonInteraction) {
ephemeral: true
});
- const check = victim ? await Moderation.permissionCheck(moderator, victim, 'ban', true) : true;
+ const check = victim ? await Moderation.permissionCheck(moderator, victim, Moderation.Action.Ban, true) : true;
if (check !== true) return interaction.reply({ content: check, ephemeral: true });
const result = await interaction.guild?.customBan({
@@ -203,7 +203,7 @@ export async function handleAutomodInteraction(interaction: ButtonInteraction) {
ephemeral: true
});
- const check = await Moderation.permissionCheck(moderator, victim, 'unmute', true);
+ const check = await Moderation.permissionCheck(moderator, victim, Moderation.Action.Unmute, true);
if (check !== true) return interaction.reply({ content: check, ephemeral: true });
const check2 = await Moderation.checkMutePermissions(interaction.guild);
diff --git a/lib/common/Appeals.ts b/lib/common/Appeals.ts
new file mode 100644
index 0000000..43c56fd
--- /dev/null
+++ b/lib/common/Appeals.ts
@@ -0,0 +1,273 @@
+import { AppealStatus, ModLog } from '#lib/models/instance/ModLog.js';
+import { colors, emojis } from '#lib/utils/Constants.js';
+import { input } from '#lib/utils/Format.js';
+import { capitalize, ModalInput } from '#lib/utils/Utils.js';
+import {
+ ActionRowBuilder,
+ ButtonBuilder,
+ ButtonStyle,
+ EmbedBuilder,
+ TextInputStyle,
+ type ButtonInteraction,
+ type ModalSubmitInteraction,
+ type Snowflake
+} from 'discord.js';
+import assert from 'node:assert/strict';
+import { Action, punishments } from './Moderation.js';
+
+type AppealBase = 'appeal_attempt' | 'appeal_submit' | 'appeal_accept' | 'appeal_deny';
+
+type RawAppealInfo = [baseId: AppealBase, punishment: `${Action}`, guildId: Snowflake, userId: Snowflake, modlogId: string];
+
+type AppealInfo = [baseId: AppealBase, punishment: Action, guildId: Snowflake, userId: Snowflake, modlogId: string];
+
+export type AppealIdString =
+ `${RawAppealInfo[0]};${RawAppealInfo[1]};${RawAppealInfo[2]};${RawAppealInfo[3]};${RawAppealInfo[4]}`;
+
+function parseAppeal(customId: AppealIdString | string): AppealInfo {
+ const [baseId, _punishment, guildId, userId, modlogId] = customId.split(';') as RawAppealInfo;
+
+ const punishment = Action[Action[_punishment] as keyof typeof Action];
+
+ return [baseId, punishment, guildId, userId, modlogId];
+}
+
+/**
+ * Handles when a user clicks the "Appeal Punishment" button on a punishment dm.
+ * @param interaction A button interaction with a custom id thar starts with "appeal_attempt;".
+ */
+export async function handleAppealAttempt(interaction: ButtonInteraction) {
+ const [baseId, punishment, guildId, userId, modlogId] = parseAppeal(interaction.customId);
+
+ const { base, past, appealCustom } = punishments[punishment];
+ const appealName = appealCustom ?? capitalize(base);
+
+ const guild = interaction.client.guilds.resolve(guildId);
+ if (!guild) {
+ return await interaction.reply(`${emojis.error} I am no longer in that server.`);
+ }
+
+ const modlog = await ModLog.findByPk(modlogId);
+ if (!modlog) {
+ return await interaction.reply(`:skull: I cannot find the modlog ${input(modlogId)}. Please report this to my developers.`);
+ }
+
+ switch (modlog.appeal) {
+ case AppealStatus.Accepted:
+ return await interaction.reply(
+ `${emojis.error} Your punishment (${input(modlogId)}) has already been appealed and accepted.`
+ );
+ case AppealStatus.Denied:
+ return await interaction.reply(
+ `${emojis.error} Your punishment (${input(modlogId)}) has already been appealed and denied.`
+ );
+ case AppealStatus.Submitted:
+ return await interaction.reply(
+ `${emojis.error} Your punishment (${input(
+ modlogId
+ )}) has already been appealed, please be patient for a moderator to review your appeal.`
+ );
+ default: {
+ const _exhaustiveCheck: AppealStatus.None = modlog.appeal;
+ }
+ }
+
+ const baseInput = {
+ style: TextInputStyle.Paragraph,
+ required: true,
+ maxLength: 1024
+ };
+
+ return await interaction.showModal({
+ customId: `appeal_submit;${punishment};${guildId};${userId};${modlogId}`,
+ title: `${appealName} Appeal`,
+ components: [
+ ModalInput({
+ ...baseInput,
+ label: `Why were you ${past}?`,
+ placeholder: `Why do you think you received a ${base}?`,
+ customId: 'appeal_reason'
+ }),
+ ModalInput({
+ ...baseInput,
+ label: 'Do you believe it was fair?',
+ placeholder: `Do you think that your ${base} is fair?`,
+ customId: 'appeal_fair'
+ }),
+ ModalInput({
+ ...baseInput,
+ label: `Why should your ${base} be removed?`,
+ placeholder: `Why do you think your ${base} be removed?`,
+ customId: 'appeal_why'
+ })
+ ]
+ });
+}
+
+/**
+ * Handles when a user submits the modal for appealing a punishment.
+ * @param interaction A modal interaction with a custom id that starts with "appeal_submit;".
+ */
+export async function handleAppealSubmit(interaction: ModalSubmitInteraction) {
+ const [baseId, punishment, guildId, userId, modlogId] = parseAppeal(interaction.customId);
+
+ const { base, past, appealCustom } = punishments[punishment];
+ const appealName = appealCustom ?? capitalize(base);
+
+ const guild = interaction.client.guilds.resolve(guildId);
+ if (!guild) {
+ return await interaction.reply(`${emojis.error} I am no longer in that server.`);
+ }
+
+ const modlog = await ModLog.findByPk(modlogId);
+ if (!modlog) {
+ return await interaction.reply(`:skull: I cannot find the modlog ${input(modlogId)}. Please report this to my developers.`);
+ }
+
+ if (modlog.appeal !== AppealStatus.None) {
+ return await interaction.reply(`Invalid appeal status: ${modlog.appeal}`);
+ }
+
+ modlog.appeal = AppealStatus.Submitted;
+ await modlog.save();
+
+ const appealChannel = await guild.getLogChannel('appeals');
+ if (!appealChannel) {
+ return await interaction.reply(`${emojis.error} I could not find an appeals channel in this server.`);
+ }
+
+ const user = await interaction.client.users.fetch(userId);
+
+ const reason = interaction.fields.getTextInputValue('appeal_reason');
+ const fair = interaction.fields.getTextInputValue('appeal_fair');
+ const why = interaction.fields.getTextInputValue('appeal_why');
+
+ const embed = new EmbedBuilder()
+ .setTitle(`${appealName} Appeal`)
+ .setColor(colors.newBlurple)
+ .setTimestamp()
+ .setFooter({ text: `CaseID: ${modlogId}` })
+ .setAuthor({ name: user.tag, iconURL: user.displayAvatarURL() })
+ .addFields(
+ { name: `Why were you ${past}?`, value: reason },
+ { name: 'Do you believe it was fair?', value: fair },
+ { name: `Why should your ${base} be removed?`, value: why }
+ );
+ return await appealChannel.send({
+ content: `Appeal submitted by ${user.tag} (${user.id})`,
+ embeds: [embed],
+ components: [
+ new ActionRowBuilder<ButtonBuilder>().addComponents(
+ new ButtonBuilder({
+ customId: `appeal_accept;${punishment};${guildId};${userId};${modlogId}`,
+ label: 'Accept Appeal',
+ style: ButtonStyle.Success
+ }),
+ new ButtonBuilder({
+ customId: `appeal_deny;${punishment};${guildId};${userId};${modlogId}`,
+ label: 'Deny Appeal',
+ style: ButtonStyle.Danger
+ })
+ )
+ ]
+ });
+}
+
+/**
+ * Handles interactions when a moderator clicks the "Accept" or "Deny" button on a punishment appeal.
+ * @param interaction A button interaction with a custom id that starts with "appeal_accept;" or "appeal_deny;".
+ */
+export async function handleAppealDecision(interaction: ButtonInteraction) {
+ const [baseId, punishment, guildId, userId, modlogId] = parseAppeal(interaction.customId);
+
+ const { base, past, appealCustom } = punishments[punishment];
+ const appealName = (appealCustom ?? base).toLowerCase();
+
+ const modlog = await ModLog.findByPk(modlogId);
+
+ if (!modlog) {
+ return await interaction.reply(`:skull: I cannot find the modlog ${input(modlogId)}. Please report this to my developers.`);
+ }
+
+ if (modlog.appeal !== AppealStatus.Submitted) {
+ return await interaction.reply(
+ `:skull: Case ${input(modlogId)} has an invalid state of ${input(modlog.appeal)}. Please report this to my developers.`
+ );
+ }
+
+ if (baseId === 'appeal_deny') {
+ modlog.appeal = AppealStatus.Denied;
+ await modlog.save();
+
+ await interaction.client.users
+ .send(userId, `Your ${appealName} appeal has been denied in ${interaction.client.guilds.resolve(guildId)!}.`)
+ .catch(() => {});
+
+ return await interaction.update({
+ content: `${emojis.cross} Appeal denied.`,
+ embeds: interaction.message.embeds,
+ components: [
+ new ActionRowBuilder<ButtonBuilder>().addComponents(
+ new ButtonBuilder({
+ disabled: true,
+ style: ButtonStyle.Danger,
+ label: 'Appeal Denied',
+ custom_id: 'noop'
+ })
+ )
+ ]
+ });
+ } else if (baseId === 'appeal_accept') {
+ modlog.appeal = AppealStatus.Accepted;
+ await modlog.save();
+
+ await interaction.client.users
+ .send(userId, `Your ${appealName} appeal has been accepted in ${interaction.client.guilds.resolve(guildId)!}.`)
+ .catch(() => {});
+
+ switch (punishment) {
+ case Action.Warn:
+ case Action.Unmute:
+ case Action.Kick:
+ case Action.Unban:
+ case Action.Untimeout:
+ case Action.Unblock:
+ case Action.RemovePunishRole:
+ assert.fail(`Cannot appeal ${appealName} (Action.${Action[punishment]})`);
+ return;
+ case Action.Mute: {
+ throw new Error('Not implemented');
+ }
+ case Action.Ban: {
+ throw new Error('Not implemented');
+ }
+ case Action.Timeout: {
+ throw new Error('Not implemented');
+ }
+ case Action.Block: {
+ throw new Error('Not implemented');
+ }
+ case Action.AddPunishRole: {
+ throw new Error('Not implemented');
+ }
+ default: {
+ const _exhaustiveCheck: never = punishment;
+ }
+ }
+
+ return await interaction.update({
+ content: `${emojis.check} Appeal accepted.`,
+ embeds: interaction.message.embeds,
+ components: [
+ new ActionRowBuilder<ButtonBuilder>().addComponents(
+ new ButtonBuilder({
+ disabled: true,
+ style: ButtonStyle.Success,
+ label: 'Appeal Accepted',
+ custom_id: 'noop'
+ })
+ )
+ ]
+ });
+ }
+}
diff --git a/lib/common/ButtonPaginator.ts b/lib/common/ButtonPaginator.ts
index 02c78ea..c8c9229 100644
--- a/lib/common/ButtonPaginator.ts
+++ b/lib/common/ButtonPaginator.ts
@@ -1,5 +1,5 @@
import { DeleteButton, type CommandMessage, type SlashMessage } from '#lib';
-import { CommandUtil } from 'discord-akairo';
+import { CommandUtil } from '@notenoughupdates/discord-akairo';
import {
ActionRowBuilder,
ButtonBuilder,
@@ -34,7 +34,7 @@ export class ButtonPaginator {
protected constructor(
protected message: CommandMessage | SlashMessage,
protected embeds: EmbedBuilder[] | APIEmbed[],
- protected text: string | null,
+ protected text: string,
protected deleteOnExit: boolean,
startOn: number
) {
@@ -199,7 +199,7 @@ export class ButtonPaginator {
public static async send(
message: CommandMessage | SlashMessage,
embeds: EmbedBuilder[] | APIEmbed[],
- text: string | null = null,
+ text: string = '',
deleteOnExit = true,
startOn = 1
) {
diff --git a/lib/common/ConfirmationPrompt.ts b/lib/common/ConfirmationPrompt.ts
index b87d9ef..631b8de 100644
--- a/lib/common/ConfirmationPrompt.ts
+++ b/lib/common/ConfirmationPrompt.ts
@@ -1,5 +1,11 @@
import { type CommandMessage, type SlashMessage } from '#lib';
-import { ActionRowBuilder, ButtonBuilder, ButtonStyle, type MessageComponentInteraction, type MessageOptions } from 'discord.js';
+import {
+ ActionRowBuilder,
+ ButtonBuilder,
+ ButtonStyle,
+ type MessageComponentInteraction,
+ type MessageCreateOptions
+} from 'discord.js';
/**
* Sends a message with buttons for the user to confirm or cancel the action.
@@ -9,7 +15,7 @@ export class ConfirmationPrompt {
* @param message The message that triggered the command
* @param messageOptions Options for sending the message
*/
- protected constructor(protected message: CommandMessage | SlashMessage, protected messageOptions: MessageOptions) {}
+ protected constructor(protected message: CommandMessage | SlashMessage, protected messageOptions: MessageCreateOptions) {}
/**
* Sends a message with buttons for the user to confirm or cancel the action.
@@ -58,7 +64,7 @@ export class ConfirmationPrompt {
* @param message The message that triggered the command
* @param sendOptions Options for sending the message
*/
- public static async send(message: CommandMessage | SlashMessage, sendOptions: MessageOptions): Promise<boolean> {
+ public static async send(message: CommandMessage | SlashMessage, sendOptions: MessageCreateOptions): Promise<boolean> {
return new ConfirmationPrompt(message, sendOptions).send();
}
}
diff --git a/lib/common/DeleteButton.ts b/lib/common/DeleteButton.ts
index 340d07f..2d053cd 100644
--- a/lib/common/DeleteButton.ts
+++ b/lib/common/DeleteButton.ts
@@ -1,5 +1,5 @@
import { PaginateEmojis, type CommandMessage, type SlashMessage } from '#lib';
-import { CommandUtil } from 'discord-akairo';
+import { CommandUtil } from '@notenoughupdates/discord-akairo';
import {
ActionRowBuilder,
ButtonBuilder,
@@ -7,7 +7,7 @@ import {
MessageComponentInteraction,
MessageEditOptions,
MessagePayload,
- type MessageOptions
+ type MessageCreateOptions
} from 'discord.js';
/**
@@ -18,7 +18,7 @@ export class DeleteButton {
* @param message The message to respond to
* @param messageOptions The send message options
*/
- protected constructor(protected message: CommandMessage | SlashMessage, protected messageOptions: MessageOptions) {}
+ protected constructor(protected message: CommandMessage | SlashMessage, protected messageOptions: MessageCreateOptions) {}
/**
* Sends a message with a button for the user to delete it.
@@ -72,7 +72,7 @@ export class DeleteButton {
* @param message The message to respond to
* @param options The send message options
*/
- public static async send(message: CommandMessage | SlashMessage, options: Omit<MessageOptions, 'components'>) {
+ public static async send(message: CommandMessage | SlashMessage, options: Omit<MessageCreateOptions, 'components'>) {
return new DeleteButton(message, options).send();
}
}
diff --git a/lib/common/HighlightManager.ts b/lib/common/HighlightManager.ts
index ca71a83..3a76a5b 100644
--- a/lib/common/HighlightManager.ts
+++ b/lib/common/HighlightManager.ts
@@ -435,6 +435,9 @@ export class HighlightManager {
}
private generateDmEmbed(message: Message, hl: HighlightWord) {
+ // janky MessageManager typings
+ assert(message.inGuild());
+
const recentMessages = message.channel.messages.cache
.filter((m) => m.createdTimestamp <= message.createdTimestamp && m.id !== message.id)
.filter((m) => m.cleanContent?.trim().length > 0)
diff --git a/lib/common/Moderation.ts b/lib/common/Moderation.ts
index 60e32c0..7697b2f 100644
--- a/lib/common/Moderation.ts
+++ b/lib/common/Moderation.ts
@@ -1,17 +1,7 @@
-import {
- ActivePunishment,
- ActivePunishmentType,
- baseMuteResponse,
- colors,
- emojis,
- format,
- Guild as GuildDB,
- humanizeDuration,
- ModLog,
- permissionsResponse,
- type ModLogType,
- type ValueOf
-} from '#lib';
+import { baseMuteResponse, permissionsResponse } from '#lib/extensions/discord.js/ExtendedGuildMember.js';
+import { ActivePunishment, ActivePunishmentType, Guild as GuildDB, ModLog, type ModLogType } from '#lib/models/index.js';
+import { colors, emojis } from '#lib/utils/Constants.js';
+import { format, humanizeDuration, ValueOf } from '#lib/utils/Utils.js';
import assert from 'assert/strict';
import {
ActionRowBuilder,
@@ -28,29 +18,178 @@ import {
type UserResolvable
} 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'
+export enum Action {
+ Warn,
+ Mute,
+ Unmute,
+ Kick,
+ Ban,
+ Unban,
+ Timeout,
+ Untimeout,
+ Block,
+ Unblock,
+ AddPunishRole,
+ RemovePunishRole
+}
+
+interface ActionInfo {
+ /**
+ * The base verb of the action
+ */
+ base: string;
+
+ /**
+ * The past tense form of the action
+ */
+ past: string;
+
+ /**
+ * Whether or not a user can appeal this action
+ */
+ appealable: boolean;
+
+ /**
+ * Whether a moderator can perform this action on themself.
+ */
+ selfInflictable: boolean;
+
+ /**
+ * Whether the action requires the target to be in the guild.
+ */
+ membershipRequired: boolean;
+
+ /**
+ * Custom appeal title, otherwise {@link ActionInfo.base} is used.
+ */
+ appealCustom?: string;
}
-enum reversedPunishMap {
- 'warn' = 'warned',
- 'mute' = 'muted',
- 'unmute' = 'unmuted',
- 'kick' = 'kicked',
- 'ban' = 'banned',
- 'unban' = 'unbanned',
- 'timeout' = 'timedout',
- 'untimeout' = 'untimedout',
- 'block' = 'blocked',
- 'unblock' = 'unblocked'
+
+export const punishments: Record<Action, ActionInfo> = {
+ [Action.Warn]: {
+ base: 'warn',
+ past: 'warned',
+ appealable: false,
+ selfInflictable: false,
+ membershipRequired: true
+ },
+ [Action.Mute]: {
+ base: 'mute',
+ past: 'muted',
+ appealable: true,
+ selfInflictable: false,
+ membershipRequired: true
+ },
+ [Action.Unmute]: {
+ base: 'unmute',
+ past: 'unmuted',
+ appealable: false,
+ selfInflictable: true,
+ membershipRequired: true
+ },
+ [Action.Kick]: {
+ base: 'kick',
+ past: 'kicked',
+ appealable: false,
+ selfInflictable: false,
+ membershipRequired: true
+ },
+ [Action.Ban]: {
+ base: 'ban',
+ past: 'banned',
+ appealable: true,
+ selfInflictable: false,
+ membershipRequired: false
+ },
+ [Action.Unban]: {
+ base: 'unban',
+ past: 'unbanned',
+ appealable: false,
+ selfInflictable: true,
+ membershipRequired: false
+ },
+ [Action.Timeout]: {
+ base: 'timeout',
+ past: 'timed out',
+ appealable: true,
+ selfInflictable: false,
+ membershipRequired: true
+ },
+ [Action.Untimeout]: {
+ base: 'untimeout',
+ past: 'untimed out',
+ appealable: false,
+ selfInflictable: true,
+ membershipRequired: true
+ },
+ [Action.Block]: {
+ base: 'block',
+ past: 'blocked',
+ appealable: true,
+ selfInflictable: false,
+ membershipRequired: true
+ },
+ [Action.Unblock]: {
+ base: 'unblock',
+ past: 'unblocked',
+ appealable: false,
+ selfInflictable: true,
+ membershipRequired: true
+ },
+ [Action.AddPunishRole]: {
+ base: 'add a punishment role to',
+ past: 'added punishment role',
+ appealable: true,
+ appealCustom: 'Punishment Role',
+ selfInflictable: false,
+ membershipRequired: true
+ },
+ [Action.RemovePunishRole]: {
+ base: 'remove a punishment role from',
+ past: 'removed punishment role',
+ appealable: false,
+ selfInflictable: true,
+ membershipRequired: true
+ }
+};
+
+interface BaseOptions {
+ /**
+ * The client.
+ */
+ client: Client;
+}
+
+interface BaseCreateModLogEntryOptions extends BaseOptions {
+ /**
+ * The type of modlog entry.
+ */
+ type: ModLogType;
+
+ /**
+ * The reason for the punishment.
+ */
+ reason: string | undefined | null;
+
+ /**
+ * The duration of the punishment.
+ */
+ duration?: number;
+
+ /**
+ * Whether the punishment is a pseudo punishment.
+ */
+ pseudo?: boolean;
+
+ /**
+ * The evidence for the punishment.
+ */
+ evidence?: string;
+
+ /**
+ * Makes the modlog entry hidden.
+ */
+ hidden?: boolean;
}
/**
@@ -65,57 +204,52 @@ enum reversedPunishMap {
export async function permissionCheck(
moderator: GuildMember,
victim: GuildMember,
- type:
- | 'mute'
- | 'unmute'
- | 'warn'
- | 'kick'
- | 'ban'
- | 'unban'
- | 'add a punishment role to'
- | 'remove a punishment role from'
- | 'block'
- | 'unblock'
- | 'timeout'
- | 'untimeout',
+ type: Action,
checkModerator = true,
force = false
): Promise<true | string> {
if (force) return true;
+ const action = punishments[type];
+
// If the victim is not in the guild anymore it will be undefined
- if ((!victim || !victim.guild) && !['ban', 'unban'].includes(type)) return true;
+ if (!victim?.guild && action.membershipRequired) return true;
- if (moderator.guild.id !== victim.guild.id) {
- throw new Error('moderator and victim not in same guild');
- }
+ assert(moderator.guild.id === victim.guild.id, 'moderator and victim should be from the same guild');
const isOwner = moderator.guild.ownerId === moderator.id;
- if (moderator.id === victim.id && !type.startsWith('un')) {
- return `${emojis.error} You cannot ${type} yourself.`;
+
+ const selfInflicted = moderator.id === victim.id;
+
+ if (selfInflicted && !action.selfInflictable) {
+ return `${emojis.error} You cannot ${action.base} yourself.`;
}
if (
moderator.roles.highest.position <= victim.roles.highest.position &&
!isOwner &&
- !(type.startsWith('un') && moderator.id === victim.id)
+ !(action.selfInflictable && selfInflicted)
) {
- return `${emojis.error} You cannot ${type} **${victim.user.tag}** because they have higher or equal role hierarchy as you do.`;
+ return `${emojis.error} You cannot ${action.base} ${format.input(
+ victim.user.tag
+ )} because they have higher or equal role hierarchy as you do.`;
}
if (
victim.roles.highest.position >= victim.guild.members.me!.roles.highest.position &&
- !(type.startsWith('un') && moderator.id === victim.id)
+ !(action.selfInflictable && selfInflicted)
) {
- return `${emojis.error} You cannot ${type} **${victim.user.tag}** because they have higher or equal role hierarchy as I do.`;
+ return `${emojis.error} You cannot ${action.base} ${format.input(
+ victim.user.tag
+ )} because they have higher or equal role hierarchy as I do.`;
}
if (
checkModerator &&
victim.permissions.has(PermissionFlagsBits.ManageMessages) &&
- !(type.startsWith('un') && moderator.id === victim.id)
+ !(action.selfInflictable && selfInflicted)
) {
if (await moderator.guild.hasFeature('modsCanPunishMods')) {
return true;
} else {
- return `${emojis.error} You cannot ${type} **${victim.user.tag}** because they are a moderator.`;
+ return `${emojis.error} You cannot ${action.base} ${format.input(victim.user.tag)} because they are a moderator.`;
}
}
return true;
@@ -129,18 +263,49 @@ export async function permissionCheck(
export async function checkMutePermissions(
guild: Guild
): Promise<ValueOf<typeof baseMuteResponse> | ValueOf<typeof permissionsResponse> | true> {
- if (!guild.members.me!.permissions.has('ManageRoles')) return permissionsResponse.MISSING_PERMISSIONS;
+ if (!guild.members.me!.permissions.has('ManageRoles')) {
+ return permissionsResponse.MISSING_PERMISSIONS;
+ }
+
const muteRoleID = await guild.getSetting('muteRole');
if (!muteRoleID) return baseMuteResponse.NO_MUTE_ROLE;
+
const muteRole = guild.roles.cache.get(muteRoleID);
if (!muteRole) return baseMuteResponse.MUTE_ROLE_INVALID;
- if (muteRole.position >= guild.members.me!.roles.highest.position || muteRole.managed)
+
+ if (muteRole.position >= guild.members.me!.roles.highest.position || muteRole.managed) {
return baseMuteResponse.MUTE_ROLE_NOT_MANAGEABLE;
+ }
return true;
}
/**
+ * Options for creating a modlog entry.
+ */
+export interface CreateModLogEntryOptions extends BaseCreateModLogEntryOptions {
+ /**
+ * The client.
+ */
+ client: Client;
+
+ /**
+ * The user that a modlog entry is created for.
+ */
+ user: GuildMemberResolvable;
+
+ /**
+ * The moderator that created the modlog entry.
+ */
+ moderator: GuildMemberResolvable;
+
+ /**
+ * The guild that the punishment is created for.
+ */
+ guild: GuildResolvable;
+}
+
+/**
* Creates a modlog entry for a punishment.
* @param options Options for creating a modlog entry.
* @param getCaseNumber Whether or not to get the case number of the entry.
@@ -166,6 +331,26 @@ export async function createModLogEntry(
}
/**
+ * Simple options for creating a modlog entry.
+ */
+export interface SimpleCreateModLogEntryOptions extends BaseCreateModLogEntryOptions {
+ /**
+ * The user that a modlog entry is created for.
+ */
+ user: Snowflake;
+
+ /**
+ * The moderator that created the modlog entry.
+ */
+ moderator: Snowflake;
+
+ /**
+ * The guild that the punishment is created for.
+ */
+ guild: Snowflake;
+}
+
+/**
* Creates a modlog entry with already resolved ids.
* @param options Options for creating a modlog entry.
* @param getCaseNumber Whether or not to get the case number of the entry.
@@ -192,6 +377,7 @@ export async function createModLogEntrySimple(
evidence: options.evidence,
hidden: options.hidden ?? false
});
+
const saveResult: ModLog | null = await modLogEntry.save().catch(async (e) => {
await options.client.utils.handleError('createModLogEntry', e);
return null;
@@ -206,6 +392,41 @@ export async function createModLogEntrySimple(
}
/**
+ * Options for creating a punishment entry.
+ */
+export interface CreatePunishmentEntryOptions extends BaseOptions {
+ /**
+ * The type of punishment.
+ */
+ type: 'mute' | 'ban' | 'role' | 'block';
+
+ /**
+ * The user that the punishment is created for.
+ */
+ user: GuildMemberResolvable;
+
+ /**
+ * The length of time the punishment lasts for.
+ */
+ duration: number | undefined;
+
+ /**
+ * The guild that the punishment is created for.
+ */
+ guild: GuildResolvable;
+
+ /**
+ * The id of the modlog that is linked to the punishment entry.
+ */
+ modlog: string;
+
+ /**
+ * Extra information for the punishment. The role for role punishments and the channel for blocks.
+ */
+ extraInfo?: Snowflake;
+}
+
+/**
* Creates a punishment entry.
* @param options Options for creating the punishment entry.
* @returns The database entry, or null if no entry is created.
@@ -221,6 +442,7 @@ export async function createPunishmentEntry(options: CreatePunishmentEntryOption
? { user, type, guild, expires, modlog: options.modlog, extraInfo: options.extraInfo }
: { user, type, guild, expires, modlog: options.modlog }
);
+
return await entry.save().catch(async (e) => {
await options.client.utils.handleError('createPunishmentEntry', e);
return null;
@@ -228,6 +450,31 @@ export async function createPunishmentEntry(options: CreatePunishmentEntryOption
}
/**
+ * Options for removing a punishment entry.
+ */
+export interface RemovePunishmentEntryOptions extends BaseOptions {
+ /**
+ * The type of punishment.
+ */
+ type: 'mute' | 'ban' | 'role' | 'block';
+
+ /**
+ * The user that the punishment is destroyed for.
+ */
+ user: GuildMemberResolvable;
+
+ /**
+ * The guild that the punishment was in.
+ */
+ guild: GuildResolvable;
+
+ /**
+ * Extra information for the punishment. The role for role punishments and the channel for blocks.
+ */
+ extraInfo?: Snowflake;
+}
+
+/**
* Destroys a punishment entry.
* @param options Options for destroying the punishment entry.
* @returns Whether or not the entry was destroyed.
@@ -250,6 +497,7 @@ export async function removePunishmentEntry(options: RemovePunishmentEntryOption
await options.client.utils.handleError('removePunishmentEntry', e);
success = false;
});
+
if (entries) {
const promises = entries.map(async (entry) =>
entry.destroy().catch(async (e) => {
@@ -270,212 +518,14 @@ export async function removePunishmentEntry(options: RemovePunishmentEntryOption
*/
function findTypeEnum(type: 'mute' | 'ban' | 'role' | 'block') {
const typeMap = {
- ['mute']: ActivePunishmentType.MUTE,
- ['ban']: ActivePunishmentType.BAN,
- ['role']: ActivePunishmentType.ROLE,
- ['block']: ActivePunishmentType.BLOCK
+ mute: ActivePunishmentType.Mute,
+ ban: ActivePunishmentType.Ban,
+ role: ActivePunishmentType.Role,
+ block: ActivePunishmentType.Block
};
return typeMap[type];
}
-export function punishmentToPresentTense(punishment: PunishmentTypeDM): PunishmentTypePresent {
- return punishMap[punishment];
-}
-
-export function 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.
- */
-export async function punishDM(options: PunishDMOptions): Promise<boolean> {
- const ending = await options.guild.getSetting('punishmentEnding');
- const dmEmbed =
- ending && ending.length && options.sendFooter
- ? new EmbedBuilder().setDescription(ending).setColor(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 ${format.input(options.guild.name)} `;
- if (options.duration !== null && options.duration !== undefined)
- content += options.duration ? `for ${humanizeDuration(options.duration)} ` : 'permanently ';
- const reason = options.reason?.trim() ? options.reason?.trim() : 'No reason provided';
- content += `for ${format.input(reason)}.`;
-
- let components;
- if (appealsEnabled && options.modlog)
- components = [
- new ActionRowBuilder<ButtonBuilder>({
- components: [
- new ButtonBuilder({
- customId: `appeal;${punishmentToPresentTense(options.punishment)};${
- options.guild.id
- };${options.client.users.resolveId(options.user)};${options.modlog}`,
- style: ButtonStyle.Primary,
- label: 'Appeal'
- }).toJSON()
- ]
- })
- ];
-
- const dmSuccess = await options.client.users
- .send(options.user, {
- content,
- embeds: dmEmbed ? [dmEmbed] : undefined,
- components
- })
- .catch(() => false);
- return !!dmSuccess;
-}
-
-interface BaseCreateModLogEntryOptions extends BaseOptions {
- /**
- * The type of modlog entry.
- */
- type: ModLogType;
-
- /**
- * The reason for the punishment.
- */
- reason: string | undefined | null;
-
- /**
- * The duration of the punishment.
- */
- duration?: number;
-
- /**
- * Whether the punishment is a pseudo punishment.
- */
- pseudo?: boolean;
-
- /**
- * The evidence for the punishment.
- */
- evidence?: string;
-
- /**
- * Makes the modlog entry hidden.
- */
- hidden?: boolean;
-}
-
-/**
- * Options for creating a modlog entry.
- */
-export interface CreateModLogEntryOptions extends BaseCreateModLogEntryOptions {
- /**
- * The client.
- */
- client: Client;
-
- /**
- * The user that a modlog entry is created for.
- */
- user: GuildMemberResolvable;
-
- /**
- * The moderator that created the modlog entry.
- */
- moderator: GuildMemberResolvable;
-
- /**
- * The guild that the punishment is created for.
- */
- guild: GuildResolvable;
-}
-
-/**
- * Simple options for creating a modlog entry.
- */
-export interface SimpleCreateModLogEntryOptions extends BaseCreateModLogEntryOptions {
- /**
- * The user that a modlog entry is created for.
- */
- user: Snowflake;
-
- /**
- * The moderator that created the modlog entry.
- */
- moderator: Snowflake;
-
- /**
- * The guild that the punishment is created for.
- */
- guild: Snowflake;
-}
-
-/**
- * Options for creating a punishment entry.
- */
-export interface CreatePunishmentEntryOptions extends BaseOptions {
- /**
- * The type of punishment.
- */
- type: 'mute' | 'ban' | 'role' | 'block';
-
- /**
- * The user that the punishment is created for.
- */
- user: GuildMemberResolvable;
-
- /**
- * The length of time the punishment lasts for.
- */
- duration: number | undefined;
-
- /**
- * The guild that the punishment is created for.
- */
- guild: GuildResolvable;
-
- /**
- * The id of the modlog that is linked to the punishment entry.
- */
- modlog: string;
-
- /**
- * Extra information for the punishment. The role for role punishments and the channel for blocks.
- */
- extraInfo?: Snowflake;
-}
-
-/**
- * Options for removing a punishment entry.
- */
-export interface RemovePunishmentEntryOptions extends BaseOptions {
- /**
- * The type of punishment.
- */
- type: 'mute' | 'ban' | 'role' | 'block';
-
- /**
- * The user that the punishment is destroyed for.
- */
- user: GuildMemberResolvable;
-
- /**
- * The guild that the punishment was in.
- */
- guild: GuildResolvable;
-
- /**
- * Extra information for the punishment. The role for role punishments and the channel for blocks.
- */
- extraInfo?: Snowflake;
-}
-
/**
* Options for sending a user a punishment dm.
*/
@@ -498,7 +548,7 @@ export interface PunishDMOptions extends BaseOptions {
/**
* The punishment that the user has received.
*/
- punishment: PunishmentTypeDM;
+ punishment: Action;
/**
* The reason the user's punishment.
@@ -522,35 +572,59 @@ export interface PunishDMOptions extends BaseOptions {
channel?: Snowflake;
}
-interface BaseOptions {
- /**
- * The client.
- */
- client: Client;
-}
+/**
+ * Notifies the specified user of their punishment.
+ * @param options Options for notifying the user.
+ * @returns Whether or not the dm was successfully sent.
+ */
+export async function punishDM(options: PunishDMOptions): Promise<boolean> {
+ const ending = await options.guild.getSetting('punishmentEnding');
+ const dmEmbed =
+ ending && ending.length && options.sendFooter
+ ? new EmbedBuilder().setDescription(ending).setColor(colors.newBlurple)
+ : undefined;
+
+ const appealsEnabled =
+ (await options.guild.hasFeature('punishmentAppeals')) && Boolean(await options.guild.getLogChannel('appeals'));
-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}`;
+ let content = `You have been ${options.punishment} `;
+ if ([Action.Block, Action.Unblock].includes(options.punishment)) {
+ assert(options.channel);
+ content += `from <#${options.channel}> `;
+ }
+ content += `in ${format.input(options.guild.name)} `;
+ if (options.duration !== null && options.duration !== undefined) {
+ content += options.duration ? `for ${humanizeDuration(options.duration)} ` : 'permanently ';
+ }
+ const reason = options.reason?.trim() ? options.reason?.trim() : 'No reason provided';
+ content += `for ${format.input(reason)}.`;
+
+ let components;
+ if (appealsEnabled && options.modlog) {
+ const punishment = options.punishment;
+ const guildId = options.guild.id;
+ const userId = options.client.users.resolveId(options.user);
+ const modlogCase = options.modlog;
+
+ components = [
+ new ActionRowBuilder<ButtonBuilder>({
+ components: [
+ new ButtonBuilder({
+ customId: `appeal_attempt;${Action[punishment]};${guildId};${userId};${modlogCase}`,
+ style: ButtonStyle.Primary,
+ label: 'Appeal Punishment'
+ })
+ ]
+ })
+ ];
+ }
+
+ const dmSuccess = await options.client.users
+ .send(options.user, {
+ content,
+ embeds: dmEmbed ? [dmEmbed] : undefined,
+ components
+ })
+ .catch(() => false);
+ return !!dmSuccess;
+}
diff --git a/lib/common/tags.ts b/lib/common/tags.ts
index 4af8783..826b820 100644
--- a/lib/common/tags.ts
+++ b/lib/common/tags.ts
@@ -1,5 +1,5 @@
-/* these functions are adapted from the common-tags npm package which is licensed under the MIT license */
-/* the JSDOCs are adapted from the @types/common-tags npm package which is licensed under the MIT license */
+/* The stripIndent, stripIndents, and format functions are adapted from the common-tags npm package which is licensed under the MIT license */
+/* The JSDOCs for said functions are adapted from the @types/common-tags npm package which is licensed under the MIT license */
/**
* Strips the **initial** indentation from the beginning of each line in a multiline string.
@@ -32,3 +32,131 @@ function format(strings: TemplateStringsArray, ...expressions: any[]) {
.replace(/^\n/, '');
return str;
}
+
+export function commas(strings: TemplateStringsArray, ...expressions: any[]) {
+ const str = strings
+ .reduce((result, string, index) => ''.concat(result, localString(expressions[index - 1]), string))
+ .replace(/[^\S\n]+$/gm, '')
+ .replace(/^\n/, '');
+
+ return str;
+}
+
+function localString(val: any) {
+ return typeof val === 'number' ? val.toLocaleString() : val;
+}
+
+export function commasStripIndents(strings: TemplateStringsArray, ...expressions: any[]) {
+ return stripIndents`${commas(strings, ...expressions)}`;
+}
+
+function splitByNewline(strings: TemplateStringsArray, ...expressions: any[]): any[][] {
+ const ret: any[][] = [];
+
+ let current: any[] = [];
+
+ for (let i = 0; i < strings.length; i++) {
+ const string = strings[i];
+ if (string.includes('\n')) {
+ // divide the string by newlines
+ const [first, ...rest] = string.split('\n');
+
+ // no point add an empty string
+ if (first !== '') {
+ // complete the current line
+ current.push(first);
+ }
+
+ // ignore empty first line
+ if (i !== 0 && current.length !== 1 && current[1] !== '') {
+ // add the current line to the list of lines
+ ret.push(current);
+ }
+
+ // handle multiple newlines
+ if (rest.length > 1) {
+ // loop though everything but the final element
+ for (const line of rest.slice(0, -1)) {
+ ret.push([line]);
+ }
+ }
+
+ // since there are no more empty newlines, add to the current line so that expressions can be added
+ const last = rest[rest.length - 1];
+ current = [last];
+ } else {
+ // if there are no newlines, just add to the current line
+ current.push(string);
+ }
+
+ // now add the expression
+ if (i < expressions.length) current.push(expressions[i]);
+ }
+
+ // add the final line
+ ret.push(current);
+
+ return ret;
+}
+
+/**
+ * Creates information fields for embeds. Commas are added to numbers.
+ * Lines are ignored if the expression is `null`, `undefined`, or `false`.
+ * Additionally, leading whitespace is removed. If the first line is empty,
+ * it is ignored.
+ * @example
+ * ```ts
+ * const value = 'value';
+ * const condition = false;
+ *
+ * embedField`
+ * Header ${value}
+ * Another Header ${condition && 50}
+ * A Third Header ${50000}`
+ *
+ * // **Header:** value
+ * // **A Third Header:** 50,000
+ * ```
+ */
+export function embedField(strings: TemplateStringsArray, ...expressions: any[]) {
+ const lines: any[][] = splitByNewline(strings, ...expressions);
+
+ // loop through each line and remove any leading whitespace
+ for (let i = 0; i < lines.length; i++) {
+ lines[i][0] = lines[i][0].replace(/^[^\S\n]+/gm, '');
+ }
+
+ const result: string[] = [];
+
+ out: for (let i = 0; i < lines.length; i++) {
+ // eslint-disable-next-line prefer-const
+ let [header, ...rest] = lines[i];
+
+ header = `**${header.trim()}:**`;
+
+ const lineContent: string[] = [];
+
+ for (let i = 0; i < rest.length; i++) {
+ const value = rest[i];
+ if (typeof value === 'string') {
+ lineContent.push(value);
+ } else if (typeof value === 'number') {
+ // add commas to numbers
+ lineContent.push(value.toLocaleString());
+ } else if (value === null || value === undefined || value === false) {
+ if (i === 0) {
+ // ignore this line
+ continue out;
+ } else {
+ throw new Error('Null or false values can only be used as the first expression in a line.');
+ }
+ } else {
+ lineContent.push(value.toString());
+ }
+ }
+
+ result.push(`${header} ${lineContent.join('')}`);
+ }
+
+ return result.join('\n');
+}
diff --git a/lib/extensions/discord-akairo/BotCommand.ts b/lib/extensions/discord-akairo/BotCommand.ts
index 11a8bad..a975667 100644
--- a/lib/extensions/discord-akairo/BotCommand.ts
+++ b/lib/extensions/discord-akairo/BotCommand.ts
@@ -11,14 +11,6 @@ import type {
import {
Command,
CommandArguments,
- type AkairoApplicationCommandAutocompleteOption,
- type AkairoApplicationCommandChannelOptionData,
- type AkairoApplicationCommandChoicesData,
- type AkairoApplicationCommandNonOptionsData,
- type AkairoApplicationCommandNumericOptionData,
- type AkairoApplicationCommandOptionData,
- type AkairoApplicationCommandSubCommandData,
- type AkairoApplicationCommandSubGroupData,
type ArgumentMatch,
type ArgumentOptions,
type ArgumentType,
@@ -29,8 +21,9 @@ import {
type ContextMenuCommand,
type SlashOption,
type SlashResolveType
-} from 'discord-akairo';
+} from '@notenoughupdates/discord-akairo';
import {
+ ApplicationCommandChannelOption,
PermissionsBitField,
type ApplicationCommandOptionChoiceData,
type ApplicationCommandOptionType,
@@ -39,7 +32,7 @@ import {
type Snowflake,
type User
} from 'discord.js';
-import _ from 'lodash';
+import { camelCase } from 'lodash-es';
import { SlashMessage } from './SlashMessage.js';
export interface OverriddenBaseArgumentType extends BaseArgumentType {
@@ -89,7 +82,7 @@ interface BaseBotArgumentOptions extends Omit<ArgumentOptions, 'type' | 'prompt'
/**
* The type used for slash commands. Set to false to disable this argument for slash commands.
*/
- slashType: AkairoApplicationCommandOptionData['type'] | false;
+ slashType: SlashOption['type'] | false;
/**
* Allows you to get a discord resolved object
@@ -111,7 +104,7 @@ interface BaseBotArgumentOptions extends Omit<ArgumentOptions, 'type' | 'prompt'
/**
* When the option type is channel, the allowed types of channels that can be selected
*/
- channelTypes?: AkairoApplicationCommandChannelOptionData['channelTypes'];
+ channelTypes?: ApplicationCommandChannelOption['channelTypes'];
/**
* The minimum value for an {@link ApplicationCommandOptionType.Integer Integer} or {@link ApplicationCommandOptionType.Number Number} option
@@ -508,8 +501,11 @@ export abstract class BotCommand extends Command {
(options_.slash || options_.slashOnly) &&
arg.slashType !== false
) {
+ // credit to https://dev.to/lucianbc/union-type-merging-in-typescript-9al
+ type AllKeys<T> = T extends any ? keyof T : never;
+
const newArg: {
- [key in SlashOptionKeys]?: any;
+ [key in AllKeys<SlashOption>]?: any;
} = {
name: arg.id,
// eslint-disable-next-line @typescript-eslint/prefer-nullish-coalescing
@@ -560,7 +556,7 @@ export abstract class BotCommand extends Command {
});
for (const arg of combined) {
- const name = _.camelCase('id' in arg ? arg.id : arg.name),
+ const name = camelCase('id' in arg ? arg.id : arg.name),
description = arg.description || '*No description provided.*',
optional = arg.optional ?? false,
autocomplete = arg.autocomplete ?? false,
@@ -607,15 +603,6 @@ export abstract class BotCommand extends Command {
public abstract override exec(message: CommandMessage | SlashMessage, args: CommandArguments): any;
}
-type SlashOptionKeys =
- | keyof AkairoApplicationCommandSubGroupData
- | keyof AkairoApplicationCommandNonOptionsData
- | keyof AkairoApplicationCommandChannelOptionData
- | keyof AkairoApplicationCommandChoicesData
- | keyof AkairoApplicationCommandAutocompleteOption
- | keyof AkairoApplicationCommandNumericOptionData
- | keyof AkairoApplicationCommandSubCommandData;
-
interface PseudoArguments extends BaseBotArgumentType {
boolean: boolean;
flag: boolean;
diff --git a/lib/extensions/discord-akairo/BotCommandHandler.ts b/lib/extensions/discord-akairo/BotCommandHandler.ts
index e9b509f..c1415e3 100644
--- a/lib/extensions/discord-akairo/BotCommandHandler.ts
+++ b/lib/extensions/discord-akairo/BotCommandHandler.ts
@@ -1,5 +1,10 @@
-import type { BotCommand, CommandMessage, SlashMessage } from '#lib';
-import { CommandHandler, CommandHandlerEvents, type Category, type CommandHandlerOptions } from 'discord-akairo';
+import type { BotCommand, CommandMessage, SlashMessage, TanzaniteClient } from '#lib';
+import {
+ CommandHandler,
+ CommandHandlerEvents,
+ type Category,
+ type CommandHandlerOptions
+} from '@notenoughupdates/discord-akairo';
import { GuildMember, PermissionResolvable, type Collection, type Message, type PermissionsString } from 'discord.js';
import { CommandHandlerEvent } from '../../utils/Constants.js';
@@ -41,6 +46,8 @@ export interface BotCommandHandlerEvents extends CommandHandlerEvents {
}
export class BotCommandHandler extends CommandHandler {
+ public declare readonly client: TanzaniteClient;
+
public declare modules: Collection<string, BotCommand>;
public declare categories: Collection<string, Category<string, BotCommand>>;
diff --git a/lib/extensions/discord-akairo/BotInhibitor.ts b/lib/extensions/discord-akairo/BotInhibitor.ts
index 8892b8b..8a53e0d 100644
--- a/lib/extensions/discord-akairo/BotInhibitor.ts
+++ b/lib/extensions/discord-akairo/BotInhibitor.ts
@@ -1,8 +1,10 @@
-import type { BotCommand, CommandMessage, InhibitorReason, InhibitorType, SlashMessage } from '#lib';
-import { Inhibitor, InhibitorOptions } from 'discord-akairo';
+import type { BotCommand, CommandMessage, InhibitorReason, InhibitorType, SlashMessage, TanzaniteClient } from '#lib';
+import { Inhibitor, InhibitorOptions } from '@notenoughupdates/discord-akairo';
import { Message } from 'discord.js';
export abstract class BotInhibitor extends Inhibitor {
+ public declare readonly client: TanzaniteClient;
+
public constructor(id: InhibitorReason, options?: BotInhibitorOptions) {
super(id, options);
}
diff --git a/lib/extensions/discord-akairo/BotInhibitorHandler.ts b/lib/extensions/discord-akairo/BotInhibitorHandler.ts
index c6f318d..05caca6 100644
--- a/lib/extensions/discord-akairo/BotInhibitorHandler.ts
+++ b/lib/extensions/discord-akairo/BotInhibitorHandler.ts
@@ -1,3 +1,6 @@
-import { InhibitorHandler } from 'discord-akairo';
+import { InhibitorHandler } from '@notenoughupdates/discord-akairo';
+import { TanzaniteClient } from './TanzaniteClient.js';
-export class BotInhibitorHandler extends InhibitorHandler {}
+export class BotInhibitorHandler extends InhibitorHandler {
+ public declare readonly client: TanzaniteClient;
+}
diff --git a/lib/extensions/discord-akairo/BotListener.ts b/lib/extensions/discord-akairo/BotListener.ts
index 4f760e2..85acce3 100644
--- a/lib/extensions/discord-akairo/BotListener.ts
+++ b/lib/extensions/discord-akairo/BotListener.ts
@@ -1,6 +1,9 @@
-import { Listener, type ListenerOptions } from 'discord-akairo';
+import { Listener, type ListenerOptions } from '@notenoughupdates/discord-akairo';
+import { TanzaniteClient } from './TanzaniteClient.js';
export abstract class BotListener extends Listener {
+ public declare readonly client: TanzaniteClient<boolean>;
+
public constructor(id: string, options: BotListenerOptions) {
super(id, options);
}
diff --git a/lib/extensions/discord-akairo/BotListenerHandler.ts b/lib/extensions/discord-akairo/BotListenerHandler.ts
index bc14a53..6a1ad4c 100644
--- a/lib/extensions/discord-akairo/BotListenerHandler.ts
+++ b/lib/extensions/discord-akairo/BotListenerHandler.ts
@@ -1,4 +1,4 @@
-import { ListenerHandler } from 'discord-akairo';
+import { ListenerHandler } from '@notenoughupdates/discord-akairo';
import type readline from 'readline';
import { TanzaniteClient } from './TanzaniteClient.js';
diff --git a/lib/extensions/discord-akairo/BotTask.ts b/lib/extensions/discord-akairo/BotTask.ts
index 09b30ed..fd0dc2e 100644
--- a/lib/extensions/discord-akairo/BotTask.ts
+++ b/lib/extensions/discord-akairo/BotTask.ts
@@ -1,3 +1,3 @@
-import { Task } from 'discord-akairo';
+import { Task } from '@notenoughupdates/discord-akairo';
export abstract class BotTask extends Task {}
diff --git a/lib/extensions/discord-akairo/BotTaskHandler.ts b/lib/extensions/discord-akairo/BotTaskHandler.ts
index b522f2c..1b4b5bd 100644
--- a/lib/extensions/discord-akairo/BotTaskHandler.ts
+++ b/lib/extensions/discord-akairo/BotTaskHandler.ts
@@ -1,3 +1,3 @@
-import { TaskHandler } from 'discord-akairo';
+import { TaskHandler } from '@notenoughupdates/discord-akairo';
export class BotTaskHandler extends TaskHandler {}
diff --git a/lib/extensions/discord-akairo/SlashMessage.ts b/lib/extensions/discord-akairo/SlashMessage.ts
index 0a6669b..b93f25f 100644
--- a/lib/extensions/discord-akairo/SlashMessage.ts
+++ b/lib/extensions/discord-akairo/SlashMessage.ts
@@ -1,3 +1,3 @@
-import { AkairoMessage } from 'discord-akairo';
+import { AkairoMessage } from '@notenoughupdates/discord-akairo';
export class SlashMessage extends AkairoMessage {}
diff --git a/lib/extensions/discord-akairo/TanzaniteClient.ts b/lib/extensions/discord-akairo/TanzaniteClient.ts
index ac09aea..a8346ba 100644
--- a/lib/extensions/discord-akairo/TanzaniteClient.ts
+++ b/lib/extensions/discord-akairo/TanzaniteClient.ts
@@ -11,8 +11,20 @@ import {
snowflake
} from '#args';
import type { Config } from '#config';
-import { patch, type PatchedElements } from '@notenoughupdates/events-intercept';
-import * as Sentry from '@sentry/node';
+import {
+ ActivePunishment,
+ Global,
+ Guild as GuildModel,
+ GuildCount,
+ Highlight,
+ Level,
+ MemberCount,
+ ModLog,
+ Reminder,
+ Shared,
+ Stat,
+ StickyRole
+} from '#lib/models/index.js';
import {
AkairoClient,
ArgumentTypeCaster,
@@ -20,7 +32,9 @@ import {
version as akairoVersion,
type ArgumentPromptData,
type OtherwiseContentSupplier
-} from 'discord-akairo';
+} from '@notenoughupdates/discord-akairo';
+import * as Sentry from '@sentry/node';
+import { patch, type PatchedElements } from '@tanzanite/events-intercept';
import {
ActivityType,
GatewayIntentBits,
@@ -32,33 +46,19 @@ import {
type Awaitable,
type If,
type Message,
- type MessageOptions,
+ type MessageCreateOptions,
type Snowflake,
type UserResolvable
} from 'discord.js';
-import type EventEmitter from 'events';
import { google } from 'googleapis';
-import path from 'path';
-import readline from 'readline';
+import { type EventEmitter } from 'node:events';
+import path from 'node:path';
+import readline from 'node:readline';
+import { fileURLToPath } from 'node:url';
import { Options as SequelizeOptions, Sequelize, Sequelize as SequelizeType } from 'sequelize';
-import { fileURLToPath } from 'url';
import { tinyColor } from '../../arguments/tinyColor.js';
import { BotCache } from '../../common/BotCache.js';
import { HighlightManager } from '../../common/HighlightManager.js';
-import {
- ActivePunishment,
- Global,
- Guild as GuildModel,
- GuildCount,
- Highlight,
- Level,
- MemberCount,
- ModLog,
- Reminder,
- Shared,
- Stat,
- StickyRole
-} from '../../models/index.js';
import { AllowedMentions } from '../../utils/AllowedMentions.js';
import { BotClientUtils } from '../../utils/BotClientUtils.js';
import { emojis } from '../../utils/Constants.js';
@@ -279,7 +279,7 @@ export class TanzaniteClient<Ready extends boolean = boolean> extends AkairoClie
const modify = async (
message: Message,
- text: string | MessagePayload | MessageOptions | OtherwiseContentSupplier,
+ text: string | MessagePayload | MessageCreateOptions | OtherwiseContentSupplier,
data: ArgumentPromptData,
replaceError: boolean
) => {
@@ -387,7 +387,7 @@ export class TanzaniteClient<Ready extends boolean = boolean> extends AkairoClie
*/
public async init() {
if (parseInt(process.versions.node.split('.')[0]) < 18) {
- void (await this.console.error('version', `Please use node <<v18.x.x>>, not <<${process.version}>>.`, false));
+ void (await this.console.error('version', `Please use node <<v18.x.x>> or greater, not <<${process.version}>>.`, false));
process.exit(2);
}
diff --git a/lib/extensions/discord.js/BotClientEvents.ts b/lib/extensions/discord.js/BotClientEvents.ts
index 941a6d8..88f67e9 100644
--- a/lib/extensions/discord.js/BotClientEvents.ts
+++ b/lib/extensions/discord.js/BotClientEvents.ts
@@ -1,4 +1,4 @@
-import type { AkairoClientEvents } from 'discord-akairo';
+import type { AkairoClientEvents } from '@notenoughupdates/discord-akairo';
import type {
ButtonInteraction,
Collection,
diff --git a/lib/extensions/discord.js/ExtendedGuild.ts b/lib/extensions/discord.js/ExtendedGuild.ts
index 6bf81ee..84db7d0 100644
--- a/lib/extensions/discord.js/ExtendedGuild.ts
+++ b/lib/extensions/discord.js/ExtendedGuild.ts
@@ -1,4 +1,5 @@
import {
+ Action,
createModLogEntry,
createModLogEntrySimple,
createPunishmentEntry,
@@ -17,15 +18,16 @@ import {
Guild,
JSONEncodable,
Message,
+ MessageCreateOptions,
MessageType,
PermissionFlagsBits,
SnowflakeUtil,
ThreadChannel,
+ WebhookCreateMessageOptions,
type APIMessage,
type GuildMember,
type GuildMemberResolvable,
type GuildTextBasedChannel,
- type MessageOptions,
type MessagePayload,
type NewsChannel,
type Snowflake,
@@ -33,10 +35,9 @@ import {
type User,
type UserResolvable,
type VoiceChannel,
- type Webhook,
- type WebhookMessageOptions
+ type Webhook
} from 'discord.js';
-import _ from 'lodash';
+import { camelCase } from 'lodash-es';
import { TanzaniteClient } from '../discord-akairo/TanzaniteClient.js';
import { banResponse, BanResponse, dmResponse, permissionsResponse, punishmentEntryRemove } from './ExtendedGuildMember.js';
@@ -91,7 +92,10 @@ interface Extension {
* @param logType The corresponding channel that the message will be sent to
* @param message The parameters for {@link TextChannel.send}
*/
- sendLogChannel(logType: GuildLogType, message: string | MessagePayload | MessageOptions): Promise<Message | null | undefined>;
+ sendLogChannel(
+ logType: GuildLogType,
+ message: string | MessagePayload | MessageCreateOptions
+ ): Promise<Message | null | undefined>;
/**
* Sends a formatted error message in a guild's error log channel
* @param title The title of the error embed
@@ -135,7 +139,7 @@ interface Extension {
declare module 'discord.js' {
export interface BaseGuild {
- client: TanzaniteClient;
+ client: TanzaniteClient<true>;
}
export interface Guild extends AnonymousGuild, Extension {}
@@ -202,7 +206,7 @@ export class ExtendedGuild extends Guild implements Extension {
public override async sendLogChannel(
logType: GuildLogType,
- message: string | MessagePayload | MessageOptions
+ message: string | MessagePayload | MessageCreateOptions
): Promise<Message | null | undefined> {
const logChannel = await this.getLogChannel(logType);
if (!logChannel || !logChannel.isTextBased()) {
@@ -220,7 +224,7 @@ export class ExtendedGuild extends Guild implements Extension {
}
public override async error(title: string, message: string): Promise<void> {
- void this.client.console.info(_.camelCase(title), message.replace(/\*\*(.*?)\*\*/g, '<<$1>>'));
+ void this.client.console.info(camelCase(title), message.replace(/\*\*(.*?)\*\*/g, '<<$1>>'));
void this.sendLogChannel('error', { embeds: [{ title: title, description: message, color: colors.error }] });
}
@@ -240,7 +244,7 @@ export class ExtendedGuild extends Guild implements Extension {
// add modlog entry
const { log: modlog } = await createModLogEntry({
client: this.client,
- type: options.duration ? ModLogType.TEMP_BAN : ModLogType.PERM_BAN,
+ type: options.duration ? ModLogType.TempBan : ModLogType.PermBan,
user: user,
moderator: moderator.id,
reason: options.reason,
@@ -257,7 +261,7 @@ export class ExtendedGuild extends Guild implements Extension {
modlog: modlog.id,
guild: this,
user: user,
- punishment: 'banned',
+ punishment: Action.Ban,
duration: options.duration ?? 0,
reason: options.reason ?? undefined,
sendFooter: true
@@ -309,7 +313,7 @@ export class ExtendedGuild extends Guild implements Extension {
// add modlog entry
const { log: modlog } = await createModLogEntrySimple({
client: this.client,
- type: ModLogType.PERM_BAN,
+ type: ModLogType.PermBan,
user: options.user,
moderator: options.moderator,
reason: options.reason,
@@ -326,7 +330,7 @@ export class ExtendedGuild extends Guild implements Extension {
modlog: modlog.id,
guild: this,
user: options.user,
- punishment: 'banned',
+ punishment: Action.Ban,
duration: 0,
reason: options.reason ?? undefined,
sendFooter: true
@@ -390,7 +394,7 @@ export class ExtendedGuild extends Guild implements Extension {
// add modlog entry
const { log: modlog } = await createModLogEntry({
client: this.client,
- type: ModLogType.UNBAN,
+ type: ModLogType.Unban,
user: user.id,
moderator: moderator.id,
reason: options.reason,
@@ -414,7 +418,7 @@ export class ExtendedGuild extends Guild implements Extension {
client: this.client,
guild: this,
user: user,
- punishment: 'unbanned',
+ punishment: Action.Unban,
reason: options.reason ?? undefined,
sendFooter: false
});
@@ -546,7 +550,7 @@ export class ExtendedGuild extends Guild implements Extension {
if (!webhook) return null;
- const sendOptions: Omit<WebhookMessageOptions, 'flags'> = {};
+ const sendOptions: Omit<WebhookCreateMessageOptions, 'flags'> = {};
const displayName = quote.member?.displayName ?? quote.author.username;
@@ -559,7 +563,7 @@ export class ExtendedGuild extends Guild implements Extension {
sendOptions.content = quote.content || undefined;
sendOptions.threadId = channel instanceof ThreadChannel ? channel.id : undefined;
sendOptions.embeds = quote.embeds.length ? quote.embeds : undefined;
- //@ts-expect-error: jank
+ // @ts-expect-error: jank
sendOptions.attachments = quote.attachments.size
? [...quote.attachments.values()].map((a) => AttachmentBuilder.from(a as JSONEncodable<AttachmentPayload>))
: undefined;
@@ -720,7 +724,9 @@ export class ExtendedGuild extends Guild implements Extension {
}
sendOptions.allowedMentions = AllowedMentions.none();
- sendOptions.username ??= quote.member?.displayName ?? quote.author.username;
+ sendOptions.username ??= (quote.member?.displayName ?? quote.author.username)
+ .replaceAll(/discord/gi, '[REDACTED]')
+ .replaceAll(/clyde/gi, '[REDACTED]');
sendOptions.avatarURL = quote.member?.displayAvatarURL({ size: 2048 }) ?? quote.author.displayAvatarURL({ size: 2048 });
return await webhook.send(sendOptions); /* .catch((e: any) => e); */
diff --git a/lib/extensions/discord.js/ExtendedGuildMember.ts b/lib/extensions/discord.js/ExtendedGuildMember.ts
index 9ef45f1..b11e9e3 100644
--- a/lib/extensions/discord.js/ExtendedGuildMember.ts
+++ b/lib/extensions/discord.js/ExtendedGuildMember.ts
@@ -8,11 +8,11 @@ import {
type Role
} from 'discord.js';
import {
+ Action,
checkMutePermissions,
createModLogEntry,
createPunishmentEntry,
punishDM,
- PunishmentTypeDM,
removePunishmentEntry
} from '../../common/Moderation.js';
import { ModLogType } from '../../models/index.js';
@@ -32,7 +32,7 @@ interface Extension {
* @returns Whether or not the dm was sent successfully.
*/
customPunishDM(
- punishment: PunishmentTypeDM,
+ punishment: Action,
reason?: string | null,
duration?: number,
modlog?: string,
@@ -119,13 +119,13 @@ interface Extension {
declare module 'discord.js' {
export interface GuildMember extends Extension {
- readonly client: TanzaniteClient;
+ readonly client: TanzaniteClient<true>;
}
}
export class ExtendedGuildMember extends GuildMember implements Extension {
public override async customPunishDM(
- punishment: PunishmentTypeDM,
+ punishment: Action,
reason?: string | null,
duration?: number,
modlog?: string,
@@ -154,7 +154,7 @@ export class ExtendedGuildMember extends GuildMember implements Extension {
const result = await createModLogEntry(
{
client: this.client,
- type: ModLogType.WARN,
+ type: ModLogType.Warn,
user: this,
moderator: moderator.id,
reason: options.reason,
@@ -169,7 +169,7 @@ export class ExtendedGuildMember extends GuildMember implements Extension {
if (!options.silent) {
// dm user
- const dmSuccess = await this.customPunishDM('warned', options.reason);
+ const dmSuccess = await this.customPunishDM(Action.Warn, options.reason);
dmSuccessEvent = dmSuccess;
if (!dmSuccess) return { result: warnResponse.DM_ERROR, caseNum: result.caseNum };
}
@@ -195,7 +195,7 @@ export class ExtendedGuildMember extends GuildMember implements Extension {
if (options.addToModlog || options.duration) {
const { log: modlog } = await createModLogEntry({
client: this.client,
- type: options.duration ? ModLogType.TEMP_PUNISHMENT_ROLE : ModLogType.PERM_PUNISHMENT_ROLE,
+ type: options.duration ? ModLogType.TempPunishmentRole : ModLogType.PermPunishmentRole,
guild: this.guild,
moderator: moderator.id,
user: this,
@@ -262,7 +262,7 @@ export class ExtendedGuildMember extends GuildMember implements Extension {
if (options.addToModlog) {
const { log: modlog } = await createModLogEntry({
client: this.client,
- type: ModLogType.REMOVE_PUNISHMENT_ROLE,
+ type: ModLogType.RemovePunishmentRole,
guild: this.guild,
moderator: moderator.id,
user: this,
@@ -362,7 +362,7 @@ export class ExtendedGuildMember extends GuildMember implements Extension {
// add modlog entry
const { log: modlog } = await createModLogEntry({
client: this.client,
- type: options.duration ? ModLogType.TEMP_MUTE : ModLogType.PERM_MUTE,
+ type: options.duration ? ModLogType.TempMute : ModLogType.PermMute,
user: this,
moderator: moderator.id,
reason: options.reason,
@@ -389,7 +389,7 @@ export class ExtendedGuildMember extends GuildMember implements Extension {
if (!options.silent) {
// dm user
- const dmSuccess = await this.customPunishDM('muted', options.reason, options.duration ?? 0, modlog.id);
+ const dmSuccess = await this.customPunishDM(Action.Mute, options.reason, options.duration ?? 0, modlog.id);
dmSuccessEvent = dmSuccess;
if (!dmSuccess) return muteResponse.DM_ERROR;
}
@@ -441,7 +441,7 @@ export class ExtendedGuildMember extends GuildMember implements Extension {
// add modlog entry
const { log: modlog } = await createModLogEntry({
client: this.client,
- type: ModLogType.UNMUTE,
+ type: ModLogType.Unmute,
user: this,
moderator: moderator.id,
reason: options.reason,
@@ -465,7 +465,7 @@ export class ExtendedGuildMember extends GuildMember implements Extension {
if (!options.silent) {
// dm user
- const dmSuccess = await this.customPunishDM('unmuted', options.reason, undefined, '', false);
+ const dmSuccess = await this.customPunishDM(Action.Unmute, options.reason, undefined, '', false);
dmSuccessEvent = dmSuccess;
if (!dmSuccess) return unmuteResponse.DM_ERROR;
}
@@ -505,7 +505,7 @@ export class ExtendedGuildMember extends GuildMember implements Extension {
// add modlog entry
const { log: modlog } = await createModLogEntry({
client: this.client,
- type: ModLogType.KICK,
+ type: ModLogType.Kick,
user: this,
moderator: moderator.id,
reason: options.reason,
@@ -517,7 +517,7 @@ export class ExtendedGuildMember extends GuildMember implements Extension {
caseID = modlog.id;
// dm user
- const dmSuccess = options.silent ? null : await this.customPunishDM('kicked', options.reason, undefined, modlog.id);
+ const dmSuccess = options.silent ? null : await this.customPunishDM(Action.Kick, options.reason, undefined, modlog.id);
dmSuccessEvent = dmSuccess ?? undefined;
// kick
@@ -564,7 +564,7 @@ export class ExtendedGuildMember extends GuildMember implements Extension {
// add modlog entry
const { log: modlog } = await createModLogEntry({
client: this.client,
- type: options.duration ? ModLogType.TEMP_BAN : ModLogType.PERM_BAN,
+ type: options.duration ? ModLogType.TempBan : ModLogType.PermBan,
user: this,
moderator: moderator.id,
reason: options.reason,
@@ -579,7 +579,7 @@ export class ExtendedGuildMember extends GuildMember implements Extension {
// dm user
const dmSuccess = options.silent
? null
- : await this.customPunishDM('banned', options.reason, options.duration ?? 0, modlog.id);
+ : await this.customPunishDM(Action.Ban, options.reason, options.duration ?? 0, modlog.id);
dmSuccessEvent = dmSuccess ?? undefined;
// ban
@@ -646,7 +646,7 @@ export class ExtendedGuildMember extends GuildMember implements Extension {
// add modlog entry
const { log: modlog } = await createModLogEntry({
client: this.client,
- type: options.duration ? ModLogType.TEMP_CHANNEL_BLOCK : ModLogType.PERM_CHANNEL_BLOCK,
+ type: options.duration ? ModLogType.TempChannelBlock : ModLogType.PermChannelBlock,
user: this,
moderator: moderator.id,
reason: options.reason,
@@ -674,7 +674,7 @@ export class ExtendedGuildMember extends GuildMember implements Extension {
? null
: await punishDM({
client: this.client,
- punishment: 'blocked',
+ punishment: Action.Block,
reason: options.reason ?? undefined,
duration: options.duration ?? 0,
modlog: modlog.id,
@@ -736,7 +736,7 @@ export class ExtendedGuildMember extends GuildMember implements Extension {
// add modlog entry
const { log: modlog } = await createModLogEntry({
client: this.client,
- type: ModLogType.CHANNEL_UNBLOCK,
+ type: ModLogType.ChannelUnblock,
user: this,
moderator: moderator.id,
reason: options.reason,
@@ -762,7 +762,7 @@ export class ExtendedGuildMember extends GuildMember implements Extension {
? null
: await punishDM({
client: this.client,
- punishment: 'unblocked',
+ punishment: Action.Unblock,
reason: options.reason ?? undefined,
guild: this.guild,
user: this,
@@ -819,7 +819,7 @@ export class ExtendedGuildMember extends GuildMember implements Extension {
// add modlog entry
const { log: modlog } = await createModLogEntry({
client: this.client,
- type: ModLogType.TIMEOUT,
+ type: ModLogType.Timeout,
user: this,
moderator: moderator.id,
reason: options.reason,
@@ -834,7 +834,7 @@ export class ExtendedGuildMember extends GuildMember implements Extension {
if (!options.silent) {
// dm user
- const dmSuccess = await this.customPunishDM('timedout', options.reason, options.duration, modlog.id);
+ const dmSuccess = await this.customPunishDM(Action.Timeout, options.reason, options.duration, modlog.id);
dmSuccessEvent = dmSuccess;
if (!dmSuccess) return timeoutResponse.DM_ERROR;
}
@@ -877,7 +877,7 @@ export class ExtendedGuildMember extends GuildMember implements Extension {
// add modlog entry
const { log: modlog } = await createModLogEntry({
client: this.client,
- type: ModLogType.REMOVE_TIMEOUT,
+ type: ModLogType.RemoveTimeout,
user: this,
moderator: moderator.id,
reason: options.reason,
@@ -891,7 +891,7 @@ export class ExtendedGuildMember extends GuildMember implements Extension {
if (!options.silent) {
// dm user
- const dmSuccess = await this.customPunishDM('untimedout', options.reason, undefined, '', false);
+ const dmSuccess = await this.customPunishDM(Action.Untimeout, options.reason, undefined, '', false);
dmSuccessEvent = dmSuccess;
if (!dmSuccess) return removeTimeoutResponse.DM_ERROR;
}
diff --git a/lib/extensions/discord.js/ExtendedMessage.ts b/lib/extensions/discord.js/ExtendedMessage.ts
index 1bb0904..07cba3d 100644
--- a/lib/extensions/discord.js/ExtendedMessage.ts
+++ b/lib/extensions/discord.js/ExtendedMessage.ts
@@ -1,11 +1,11 @@
-import { CommandUtil } from 'discord-akairo';
+import { CommandUtil } from '@notenoughupdates/discord-akairo';
import { Message, type Client } from 'discord.js';
import type { RawMessageData } from 'discord.js/typings/rawDataTypes.js';
-export class ExtendedMessage<Cached extends boolean = boolean> extends Message<Cached> {
- public declare util: CommandUtil<Message>;
+export class ExtendedMessage<InGuild extends boolean = boolean> extends Message<InGuild> {
+ public declare util: CommandUtil<Message<InGuild>>;
- public constructor(client: Client, data: RawMessageData) {
+ public constructor(client: Client<true>, data: RawMessageData) {
super(client, data);
this.util = new CommandUtil(client.commandHandler, this);
}
diff --git a/lib/extensions/discord.js/ExtendedUser.ts b/lib/extensions/discord.js/ExtendedUser.ts
index 7846a70..8f9d27b 100644
--- a/lib/extensions/discord.js/ExtendedUser.ts
+++ b/lib/extensions/discord.js/ExtendedUser.ts
@@ -14,7 +14,7 @@ interface Extension {
declare module 'discord.js' {
export interface User extends Extension {
- readonly client: TanzaniteClient;
+ readonly client: TanzaniteClient<true>;
}
}
diff --git a/lib/global.ts b/lib/global.ts
index 0a0bcca..d3419c7 100644
--- a/lib/global.ts
+++ b/lib/global.ts
@@ -1,5 +1,7 @@
/* eslint-disable */
+declare const nodeFetch: typeof import('node-fetch').default;
+
declare global {
interface ReadonlyArray<T> {
includes<S, R extends `${Extract<S, string>}`>(
@@ -8,6 +10,8 @@ declare global {
fromIndex?: number
): searchElement is R & S;
}
+
+ var fetch: typeof nodeFetch;
}
export {};
diff --git a/lib/index.ts b/lib/index.ts
index fc7bb4c..d486d68 100644
--- a/lib/index.ts
+++ b/lib/index.ts
@@ -3,6 +3,7 @@ export * from './automod/AutomodShared.js';
export * from './automod/MemberAutomod.js';
export * from './automod/MessageAutomod.js';
export * from './automod/PresenceAutomod.js';
+export * from './common/Appeals.js';
export * from './common/BotCache.js';
export * from './common/ButtonPaginator.js';
export * from './common/CanvasProgressBar.js';
@@ -10,12 +11,9 @@ export * from './common/ConfirmationPrompt.js';
export * from './common/DeleteButton.js';
export * as Moderation from './common/Moderation.js';
export type {
- AppealButtonId,
CreateModLogEntryOptions,
CreatePunishmentEntryOptions,
PunishDMOptions,
- PunishmentTypeDM,
- PunishmentTypePresent,
RemovePunishmentEntryOptions,
SimpleCreateModLogEntryOptions
} from './common/Moderation.js';
diff --git a/lib/models/instance/ActivePunishment.ts b/lib/models/instance/ActivePunishment.ts
index 9bd9d01..1b57f47 100644
--- a/lib/models/instance/ActivePunishment.ts
+++ b/lib/models/instance/ActivePunishment.ts
@@ -4,10 +4,10 @@ import { DataTypes, type Sequelize } from 'sequelize';
import { BaseModel } from '../BaseModel.js';
export enum ActivePunishmentType {
- BAN = 'BAN',
- MUTE = 'MUTE',
- ROLE = 'ROLE',
- BLOCK = 'BLOCK'
+ Ban = 'BAN',
+ Mute = 'MUTE',
+ Role = 'ROLE',
+ Block = 'BLOCK'
}
export interface ActivePunishmentModel {
diff --git a/lib/models/instance/Guild.ts b/lib/models/instance/Guild.ts
index 72091ca..462beee 100644
--- a/lib/models/instance/Guild.ts
+++ b/lib/models/instance/Guild.ts
@@ -210,7 +210,7 @@ export const guildSettingsObj = asGuildSetting({
name: 'Auto Publish Channels',
description: 'Channels were every message is automatically published.',
type: 'channel-array',
- subType: [ChannelType.GuildNews]
+ subType: [ChannelType.GuildAnnouncement]
},
welcomeChannel: {
name: 'Welcome Channel',
@@ -218,10 +218,10 @@ export const guildSettingsObj = asGuildSetting({
type: 'channel',
subType: [
ChannelType.GuildText,
- ChannelType.GuildNews,
- ChannelType.GuildNewsThread,
- ChannelType.GuildPublicThread,
- ChannelType.GuildPrivateThread
+ ChannelType.GuildAnnouncement,
+ ChannelType.AnnouncementThread,
+ ChannelType.PublicThread,
+ ChannelType.PrivateThread
]
},
muteRole: {
diff --git a/lib/models/instance/Level.ts b/lib/models/instance/Level.ts
index e22d63b..27def46 100644
--- a/lib/models/instance/Level.ts
+++ b/lib/models/instance/Level.ts
@@ -18,6 +18,9 @@ export interface LevelModelCreationAttributes {
* Leveling information for a user in a guild.
*/
export class Level extends BaseModel<LevelModel, LevelModelCreationAttributes> implements LevelModel {
+ public static MAX_XP = 2147483647;
+ public static MAX_LEVEL = Level.convertXpToLevel(Level.MAX_XP);
+
/**
* The user's id.
*/
diff --git a/lib/models/instance/ModLog.ts b/lib/models/instance/ModLog.ts
index 324ad83..7a1a60a 100644
--- a/lib/models/instance/ModLog.ts
+++ b/lib/models/instance/ModLog.ts
@@ -4,104 +4,98 @@ import { DataTypes, type Sequelize } from 'sequelize';
import { BaseModel } from '../BaseModel.js';
export enum ModLogType {
- PERM_BAN = 'PERM_BAN',
- TEMP_BAN = 'TEMP_BAN',
- UNBAN = 'UNBAN',
- KICK = 'KICK',
- PERM_MUTE = 'PERM_MUTE',
- TEMP_MUTE = 'TEMP_MUTE',
- UNMUTE = 'UNMUTE',
- WARN = 'WARN',
- PERM_PUNISHMENT_ROLE = 'PERM_PUNISHMENT_ROLE',
- TEMP_PUNISHMENT_ROLE = 'TEMP_PUNISHMENT_ROLE',
- REMOVE_PUNISHMENT_ROLE = 'REMOVE_PUNISHMENT_ROLE',
- PERM_CHANNEL_BLOCK = 'PERM_CHANNEL_BLOCK',
- TEMP_CHANNEL_BLOCK = 'TEMP_CHANNEL_BLOCK',
- CHANNEL_UNBLOCK = 'CHANNEL_UNBLOCK',
- TIMEOUT = 'TIMEOUT',
- REMOVE_TIMEOUT = 'REMOVE_TIMEOUT'
+ PermBan = 'PERM_BAN',
+ TempBan = 'TEMP_BAN',
+ Unban = 'UNBAN',
+ Kick = 'KICK',
+ PermMute = 'PERM_MUTE',
+ TempMute = 'TEMP_MUTE',
+ Unmute = 'UNMUTE',
+ Warn = 'WARN',
+ PermPunishmentRole = 'PERM_PUNISHMENT_ROLE',
+ TempPunishmentRole = 'TEMP_PUNISHMENT_ROLE',
+ RemovePunishmentRole = 'REMOVE_PUNISHMENT_ROLE',
+ PermChannelBlock = 'PERM_CHANNEL_BLOCK',
+ TempChannelBlock = 'TEMP_CHANNEL_BLOCK',
+ ChannelUnblock = 'CHANNEL_UNBLOCK',
+ Timeout = 'TIMEOUT',
+ RemoveTimeout = 'REMOVE_TIMEOUT'
}
-export interface ModLogModel {
- id: string;
- type: ModLogType;
- user: Snowflake;
- moderator: Snowflake;
- reason: string | null;
- duration: number | null;
- guild: Snowflake;
- evidence: string;
- pseudo: boolean;
- hidden: boolean;
-}
-
-export interface ModLogModelCreationAttributes {
- id?: string;
- type: ModLogType;
- user: Snowflake;
- moderator: Snowflake;
- reason?: string | null;
- duration?: number;
- guild: Snowflake;
- evidence?: string;
- pseudo?: boolean;
- hidden?: boolean;
+export enum AppealStatus {
+ None = 'NONE',
+ Submitted = 'SUBMITTED',
+ Accepted = 'ACCEPTED',
+ Denied = 'DENIED'
}
-/**
- * A mod log case.
- */
-export class ModLog extends BaseModel<ModLogModel, ModLogModelCreationAttributes> implements ModLogModel {
+export interface ModLogModel {
/**
* The primary key of the modlog entry.
*/
- public declare id: string;
-
+ id: string;
/**
* The type of punishment.
*/
- public declare type: ModLogType;
-
+ type: ModLogType;
/**
* The user being punished.
*/
- public declare user: Snowflake;
-
+ user: Snowflake;
/**
* The user carrying out the punishment.
*/
- public declare moderator: Snowflake;
-
+ moderator: Snowflake;
/**
* The reason the user is getting punished.
*/
- public declare reason: string | null;
-
+ reason: string | null;
/**
* The amount of time the user is getting punished for.
*/
- public declare duration: number | null;
-
+ duration: number | null;
/**
* The guild the user is getting punished in.
*/
- public declare guild: Snowflake;
-
+ guild: Snowflake;
/**
* Evidence of what the user is getting punished for.
*/
- public declare evidence: string;
-
+ evidence: string;
/**
* Not an actual modlog just used so a punishment entry can be made.
*/
- public declare pseudo: boolean;
-
+ pseudo: boolean;
/**
* Hides from the modlog command unless show hidden is specified.
*/
- public declare hidden: boolean;
+ hidden: boolean;
+ /**
+ * The status of an appeal for this punishment
+ */
+ appeal: AppealStatus;
+}
+export interface ModLogModelCreationAttributes {
+ id?: string;
+ type: ModLogType;
+ user: Snowflake;
+ moderator: Snowflake;
+ reason?: string | null;
+ duration?: number;
+ guild: Snowflake;
+ evidence?: string;
+ pseudo?: boolean;
+ hidden?: boolean;
+ appeal?: AppealStatus;
+}
+
+export interface ModLog extends ModLogModel {}
+
+/**
+ * A mod log case.
+ */
+export class ModLog extends BaseModel<ModLogModel, ModLogModelCreationAttributes> {
/**
* Initializes the model.
* @param sequelize The sequelize instance.
@@ -118,7 +112,8 @@ export class ModLog extends BaseModel<ModLogModel, ModLogModelCreationAttributes
guild: { type: DataTypes.STRING, references: { model: 'Guilds', key: 'id' } },
evidence: { type: DataTypes.TEXT, allowNull: true },
pseudo: { type: DataTypes.BOOLEAN, allowNull: false, defaultValue: false },
- hidden: { type: DataTypes.BOOLEAN, allowNull: false, defaultValue: false }
+ hidden: { type: DataTypes.BOOLEAN, allowNull: false, defaultValue: false },
+ appeal: { type: DataTypes.STRING, allowNull: false, defaultValue: AppealStatus.None }
},
{ sequelize }
);
diff --git a/lib/types/misc.ts b/lib/types/misc.ts
index 5bf760c..5f28dae 100644
--- a/lib/types/misc.ts
+++ b/lib/types/misc.ts
@@ -1,14 +1,14 @@
import type {
InteractionReplyOptions,
+ MessageCreateOptions,
MessageEditOptions,
- MessageOptions,
MessagePayload,
- ReplyMessageOptions,
+ MessageReplyOptions,
WebhookEditMessageOptions
} from 'discord.js';
-export type ReplyMessageType = string | MessagePayload | ReplyMessageOptions;
+export type ReplyMessageType = string | MessagePayload | MessageReplyOptions;
export type EditMessageType = string | MessageEditOptions | MessagePayload;
export type SlashSendMessageType = string | MessagePayload | InteractionReplyOptions;
export type SlashEditMessageType = string | MessagePayload | WebhookEditMessageOptions;
-export type SendMessageType = string | MessagePayload | MessageOptions;
+export type SendMessageType = string | MessagePayload | MessageCreateOptions;
diff --git a/lib/utils/Arg.ts b/lib/utils/Arg.ts
index 80ca878..803230b 100644
--- a/lib/utils/Arg.ts
+++ b/lib/utils/Arg.ts
@@ -1,5 +1,5 @@
import type { BaseBotArgumentType, BotArgumentType, BotArgumentTypeCaster, CommandMessage, SlashMessage } from '#lib';
-import { Argument, type Command, type Flag, type ParsedValuePredicate } from 'discord-akairo';
+import { Argument, type Command, type Flag, type ParsedValuePredicate } from '@notenoughupdates/discord-akairo';
import { type Message } from 'discord.js';
/**
diff --git a/lib/utils/BotClientUtils.ts b/lib/utils/BotClientUtils.ts
index 4b2c99b..6837237 100644
--- a/lib/utils/BotClientUtils.ts
+++ b/lib/utils/BotClientUtils.ts
@@ -21,7 +21,7 @@ import {
type Snowflake,
type UserResolvable
} from 'discord.js';
-import _ from 'lodash';
+import { camelCase } from 'lodash-es';
import { emojis, Pronoun, PronounCode, pronounMapping, regex } from './Constants.js';
import { generateErrorEmbed } from './ErrorHandler.js';
import { addOrRemoveFromArray, formatError, inspect } from './Utils.js';
@@ -329,7 +329,7 @@ export class BotClientUtils {
* @param error
*/
public async handleError(context: string, error: Error) {
- await this.client.console.error(_.camelCase(context), `An error occurred:\n${formatError(error, false)}`, false);
+ await this.client.console.error(camelCase(context), `An error occurred:\n${formatError(error, false)}`, false);
await this.client.console.channelError({
embeds: await generateErrorEmbed(this.client, { type: 'unhandledRejection', error: error, context })
});
@@ -382,6 +382,7 @@ export class BotClientUtils {
public async uploadImageToImgur(image: string) {
const clientId = this.client.config.credentials.imgurClientId;
+ // @ts-expect-error: missing global types
const formData = new FormData();
formData.append('type', 'base64');
formData.append('image', image);
diff --git a/lib/utils/Constants.ts b/lib/utils/Constants.ts
index dd65e28..5ecbce2 100644
--- a/lib/utils/Constants.ts
+++ b/lib/utils/Constants.ts
@@ -1,4 +1,4 @@
-import { default as deepLock } from 'deep-lock';
+import deepLock from '@tanzanite/deep-lock';
import { Colors, GuildFeature, Snowflake } from 'discord.js';
const rawCapeUrl = 'https://raw.githubusercontent.com/NotEnoughUpdates/capes/master/';
@@ -294,6 +294,7 @@ export const mappings = deepLock({
AUTO_MODERATION: { name: 'Auto Moderation', important: false, emoji: '<:autoModeration:1010579417942200321>', weight: 33 },
MEMBER_PROFILES: { name: 'Member Profiles', important: false, emoji: '<:memberProfiles:1010580480409747547>', weight: 34 },
NEW_THREAD_PERMISSIONS: { name: 'New Thread Permissions', important: false, emoji: '<:newThreadPermissions:1010580968442171492>', weight: 35 },
+ [GuildFeature.InvitesDisabled]: { name: 'Invites Disabled', important: false, emoji: null, weight: 36 },
},
regions: {
diff --git a/lib/utils/ErrorHandler.ts b/lib/utils/ErrorHandler.ts
index 3f8be89..ea4a026 100644
--- a/lib/utils/ErrorHandler.ts
+++ b/lib/utils/ErrorHandler.ts
@@ -1,4 +1,4 @@
-import { AkairoMessage, Command } from 'discord-akairo';
+import { AkairoMessage, Command } from '@notenoughupdates/discord-akairo';
import { ChannelType, Client, EmbedBuilder, escapeInlineCode, GuildTextBasedChannel, Message } from 'discord.js';
import { BotCommandHandlerEvents } from '../extensions/discord-akairo/BotCommandHandler.js';
import { SlashMessage } from '../extensions/discord-akairo/SlashMessage.js';
diff --git a/lib/utils/Utils.ts b/lib/utils/Utils.ts
index 13806ec..ea70abf 100644
--- a/lib/utils/Utils.ts
+++ b/lib/utils/Utils.ts
@@ -1,9 +1,11 @@
+import { Util as AkairoUtil } from '@notenoughupdates/discord-akairo';
import { humanizeDuration as humanizeDurationMod } from '@notenoughupdates/humanize-duration';
+import deepLock from '@tanzanite/deep-lock';
import assert from 'assert/strict';
import cp from 'child_process';
-import deepLock from 'deep-lock';
-import { Util as AkairoUtil } from 'discord-akairo';
import {
+ ActionRowBuilder,
+ APITextInputComponent,
Constants as DiscordConstants,
EmbedBuilder,
Message,
@@ -11,6 +13,8 @@ import {
PermissionFlagsBits,
PermissionsBitField,
PermissionsString,
+ TextInputBuilder,
+ TextInputComponentData,
type APIEmbed,
type APIMessage,
type CommandInteraction,
@@ -159,7 +163,7 @@ export async function slashRespond(
delete (newResponseOptions as InteractionReplyOptions).ephemeral; // Cannot change a preexisting message to be ephemeral
return (await interaction.editReply(newResponseOptions)) as Message | APIMessage;
} else {
- await interaction.reply(newResponseOptions);
+ await interaction.reply(newResponseOptions as SlashSendMessageType);
return await interaction.fetchReply().catch(() => undefined);
}
}
@@ -547,3 +551,9 @@ export function deepWriteable<T>(obj: T): DeepWritable<T> {
export function formatPerms(permissions: PermissionsString[]) {
return permissions.map((p) => `\`${mappings.permissions[p]?.name ?? p}\``).join(', ');
}
+
+export function ModalInput(options: Partial<TextInputComponentData | APITextInputComponent>): ActionRowBuilder<TextInputBuilder> {
+ return new ActionRowBuilder<TextInputBuilder>({
+ components: [new TextInputBuilder(options)]
+ });
+}
diff --git a/neu-item-repo b/neu-item-repo
-Subproject 17617a4517877c3e514bee9445668f3b4d83459
+Subproject f18a467e17e845bb79404ed329e14a73e389134
diff --git a/neu-item-repo-dangerous b/neu-item-repo-dangerous
-Subproject 17617a4517877c3e514bee9445668f3b4d83459
+Subproject f18a467e17e845bb79404ed329e14a73e389134
diff --git a/package.json b/package.json
index 8db194c..3f5250b 100644
--- a/package.json
+++ b/package.json
@@ -21,7 +21,7 @@
],
"license": "CC-BY-NC-SA-4.0",
"scripts": {
- "build": "yarn rimraf dist && yarn tsc -b",
+ "build": "rm -rf dist && yarn tsc -b",
"build:no-emit": "yarn tsc --noEmit",
"build:keep": "yarn tsc -b",
"start": "yarn build && yarn start:raw",
@@ -33,7 +33,7 @@
"format": "yarn prettier . --write",
"format:check": "yarn prettier . --check",
"lint": "yarn eslint src lib config tests",
- "upgrade": "yarn rimraf yarn.lock && yarn cache clean && yarn install && yarn set version latest && git submodule update --recursive --remote && yarn upgrade-interactive",
+ "upgrade": "rm -f yarn.lock && yarn cache clean && yarn install && yarn set version latest && git submodule update --recursive --remote && yarn upgrade-interactive",
"upgrade:sdk": "yarn dlx @yarnpkg/sdks vscode",
"beta": "git push && git checkout beta && git merge master && git push && git checkout master",
"deploy:beta": "pm2 deploy ecosystem.config.cjs beta",
@@ -63,67 +63,66 @@
"default": "./config/index.js"
}
},
+ "disabled-dependencies": {
+ "gif-to-apng": "^0.1.2"
+ },
"dependencies": {
- "@discordjs/builders": "^1.1.0",
- "@discordjs/rest": "^1.0.1",
+ "@discordjs/builders": "^1.2.0",
+ "@discordjs/rest": "^1.2.0",
"@ironm00n/nbt-ts": "^1.4.0",
- "@napi-rs/canvas": "^0.1.29",
- "@notenoughupdates/discord.js-minesweeper": "^1.0.10",
- "@notenoughupdates/events-intercept": "^3.0.1",
+ "@napi-rs/canvas": "^0.1.30",
+ "@notenoughupdates/discord-akairo": "^10.0.0-dev.1664158089.48d6368",
"@notenoughupdates/humanize-duration": "^4.0.1",
- "@notenoughupdates/simplify-number": "^1.0.1",
- "@notenoughupdates/wolfram-alpha-api": "^1.0.2",
- "@sentry/integrations": "^7.11.1",
- "@sentry/node": "^7.11.1",
- "@sentry/tracing": "^7.11.1",
+ "@sentry/integrations": "^7.13.0",
+ "@sentry/node": "^7.13.0",
+ "@sentry/tracing": "^7.13.0",
+ "@tanzanite/deep-lock": "^1.1.1",
+ "@tanzanite/discord.js-minesweeper": "^1.2.0",
+ "@tanzanite/events-intercept": "^3.1.0",
+ "@tanzanite/simplify-number": "^2.0.1",
+ "@tanzanite/wolfram-alpha": "^1.1.0",
"chalk": "^5.0.1",
- "deep-lock": "^1.0.0",
- "discord-akairo": "npm:@notenoughupdates/discord-akairo@dev",
- "discord-api-types": "0.37.1",
- "discord.js": "npm:@notenoughupdates/discord.js@forum",
+ "discord-api-types": "0.37.10",
+ "discord.js": "^14.5.0",
"fuse.js": "^6.6.2",
- "gif-to-apng": "^0.1.2",
- "googleapis": "^107.0.0",
- "lodash": "^4.17.21",
- "mathjs": "^11.1.0",
+ "googleapis": "^108.0.0",
+ "lodash-es": "^4.17.21",
+ "mathjs": "^11.2.1",
"nanoid": "^4.0.0",
"numeral": "^2.0.6",
"pg": "^8.8.0",
"pg-hstore": "^2.3.4",
"prettier": "^2.7.1",
"pretty-bytes": "^6.0.0",
- "rimraf": "^3.0.2",
- "sequelize": "6.21.4",
+ "sequelize": "6.23.1",
"tinycolor2": "^1.4.2",
- "typescript": "^4.8.2",
- "vm2": "^3.9.10"
+ "typescript": "^4.8.3",
+ "vm2": "^3.9.11"
},
"devDependencies": {
"@sapphire/snowflake": "^3.2.2",
- "@sentry/types": "^7.11.1",
+ "@sentry/types": "^7.13.0",
"@types/eslint": "^8.4.6",
- "@types/express": "^4.17.13",
- "@types/lodash": "^4.14.184",
- "@types/node": "^18.7.13",
+ "@types/express": "^4.17.14",
+ "@types/lodash-es": "^4",
+ "@types/node": "^18.7.21",
+ "@types/node-fetch": "^2.6.2",
"@types/numeral": "^2.0.2",
"@types/pg": "^8.6.5",
- "@types/prettier": "^2.7.0",
- "@types/rimraf": "^3.0.2",
+ "@types/prettier": "^2.7.1",
"@types/tinycolor2": "^1.4.3",
- "@types/validator": "^13.7.5",
- "@typescript-eslint/eslint-plugin": "^5.35.1",
- "@typescript-eslint/parser": "^5.35.1",
- "eslint": "^8.23.0",
+ "@types/validator": "^13.7.7",
+ "@typescript-eslint/eslint-plugin": "^5.38.0",
+ "@typescript-eslint/parser": "^5.38.0",
+ "eslint": "^8.24.0",
"eslint-config-prettier": "^8.5.0",
"eslint-plugin-deprecation": "^1.3.2",
"ts-essentials": "^9.3.0",
- "vitest": "^0.22.1"
+ "vitest": "^0.23.4"
},
"packageManager": "yarn@3.2.3",
"resolutions": {
- "@discordjs/builders@workspace:^": "^1.1.0",
- "@discordjs/collection@workspace:^": "^1.0.1",
- "@discordjs/rest@workspace:^": "^1.0.1",
- "tslib": "^2.4.0"
+ "tslib": "^2.4.0",
+ "discord.js": "npm:@notenoughupdates/discord.js@dev"
}
}
diff --git a/src/bot.ts b/src/bot.ts
index 486eb2e..99d3ee3 100644
--- a/src/bot.ts
+++ b/src/bot.ts
@@ -1,26 +1,38 @@
+import { performance } from 'node:perf_hooks';
+performance.mark('processStart');
+
console.log('Tanzanite is Starting');
-import { init } from '../lib/utils/Logger.js';
+import { init } from '#lib/utils/Logger.js';
// creates proxies on console.log and console.warn
// also starts a REPL session
init();
import { config } from '#config';
-import { dirname } from 'path';
-import { fileURLToPath } from 'url';
-import { Sentry } from '../lib/common/Sentry.js';
-import { TanzaniteClient } from '../lib/extensions/discord-akairo/TanzaniteClient.js';
+import { Sentry } from '#lib/common/Sentry.js';
+import { TanzaniteClient } from '#lib/extensions/discord-akairo/TanzaniteClient.js';
+import { dirname } from 'node:path';
+import { fileURLToPath } from 'node:url';
const isDry = process.argv.includes('dry');
-if (!isDry && config.credentials.sentryDsn !== null) new Sentry(dirname(fileURLToPath(import.meta.url)) || process.cwd(), config);
+
+if (!isDry && config.credentials.sentryDsn !== null) {
+ new Sentry(dirname(fileURLToPath(import.meta.url)) || process.cwd(), config);
+}
+
TanzaniteClient.extendStructures();
+
const client = new TanzaniteClient(config);
-// @ts-ignore: for debugging purposes
+// @ts-ignore: I don't want to add this to the global typings, this is only for debugging purposes
global.client = client;
-if (!isDry) await client.dbPreInit();
+if (!isDry) {
+ await client.dbPreInit();
+}
+
await client.init();
+
if (isDry) {
process.exit(0);
} else {
diff --git a/src/commands/config/config.ts b/src/commands/config/config.ts
index adc41d8..4d38c54 100644
--- a/src/commands/config/config.ts
+++ b/src/commands/config/config.ts
@@ -13,8 +13,8 @@ import {
type GuildSettingType,
type SlashMessage
} from '#lib';
+import { ExtSub, type ArgumentGeneratorReturn, type SlashOption } from '@notenoughupdates/discord-akairo';
import assert from 'assert/strict';
-import { type ArgumentGeneratorReturn, type SlashOption } from 'discord-akairo';
import {
ActionRowBuilder,
ApplicationCommandOptionType,
@@ -32,10 +32,9 @@ import {
User,
type Message,
type MessageComponentInteraction,
- type MessageOptions
+ type MessageCreateOptions
} from 'discord.js';
-import _ from 'lodash';
-const { camelCase, snakeCase } = _;
+import { camelCase, snakeCase } from 'lodash-es';
export const arrayActions = ['view' as const, 'add' as const, 'remove' as const, 'clear' as const];
export type ArrayActions = typeof arrayActions[number];
@@ -79,7 +78,7 @@ export default class ConfigCommand extends BotCommand {
description: `Manage the server's ${loweredName}`,
type: ApplicationCommandOptionType.SubcommandGroup,
options: isArray
- ? [
+ ? ([
{
name: 'view',
description: `View the server's ${loweredName}.`,
@@ -118,8 +117,8 @@ export default class ConfigCommand extends BotCommand {
description: `Remove all values from a server's ${loweredName}.`,
type: ApplicationCommandOptionType.Subcommand
}
- ]
- : [
+ ] as ExtSub[])
+ : ([
{
name: 'view',
description: `View the server's ${loweredName}.`,
@@ -144,7 +143,7 @@ export default class ConfigCommand extends BotCommand {
description: `Delete the server's ${loweredName}.`,
type: ApplicationCommandOptionType.Subcommand
}
- ]
+ ] as ExtSub[])
};
}),
channel: 'guild',
@@ -309,7 +308,7 @@ export default class ConfigCommand extends BotCommand {
public async generateMessageOptions(
message: CommandMessage | SlashMessage,
setting?: undefined | keyof typeof guildSettingsObj
- ): Promise<MessageOptions & InteractionUpdateOptions> {
+ ): Promise<MessageCreateOptions & InteractionUpdateOptions> {
assert(message.inGuild());
const settingsEmbed = new EmbedBuilder().setColor(colors.default);
diff --git a/src/commands/config/disable.ts b/src/commands/config/disable.ts
index 6dd94a6..776ecf0 100644
--- a/src/commands/config/disable.ts
+++ b/src/commands/config/disable.ts
@@ -10,9 +10,9 @@ import {
} from '#lib';
import assert from 'assert/strict';
import { ApplicationCommandOptionType, AutocompleteInteraction } from 'discord.js';
-import { default as Fuse } from 'fuse.js';
-assert(Fuse);
+// todo: remove this bullshit once typescript gets its shit together
+const Fuse = (await import('fuse.js')).default as unknown as typeof import('fuse.js').default;
export default class DisableCommand extends BotCommand {
private static blacklistedCommands = ['eval', 'disable'];
diff --git a/src/commands/config/log.ts b/src/commands/config/log.ts
index 0c74ce7..6d0f594 100644
--- a/src/commands/config/log.ts
+++ b/src/commands/config/log.ts
@@ -8,8 +8,8 @@ import {
type GuildLogType,
type SlashMessage
} from '#lib';
+import { ArgumentGeneratorReturn } from '@notenoughupdates/discord-akairo';
import assert from 'assert/strict';
-import { ArgumentGeneratorReturn } from 'discord-akairo';
import { ApplicationCommandOptionType, ChannelType } from 'discord.js';
export default class LogCommand extends BotCommand {
@@ -38,10 +38,10 @@ export default class LogCommand extends BotCommand {
slashType: ApplicationCommandOptionType.Channel,
channelTypes: [
ChannelType.GuildText,
- ChannelType.GuildNews,
- ChannelType.GuildNewsThread,
- ChannelType.GuildPublicThread,
- ChannelType.GuildPrivateThread
+ ChannelType.GuildAnnouncement,
+ ChannelType.AnnouncementThread,
+ ChannelType.PublicThread,
+ ChannelType.PrivateThread
],
only: 'slash'
}
diff --git a/src/commands/dev/eval.ts b/src/commands/dev/eval.ts
index 83168e0..5fe21c0 100644
--- a/src/commands/dev/eval.ts
+++ b/src/commands/dev/eval.ts
@@ -283,7 +283,7 @@ export default class EvalCommand extends BotCommand {
if (!err && proto) embed.addFields({ name: ':gear: Proto', value: proto });
if (!silent || message.util.isSlashMessage(message)) {
- await message.util.reply({ content: null, embeds: [embed] });
+ await message.util.reply({ content: '', embeds: [embed] });
} else {
const success = await message.author.send({ embeds: [embed] }).catch(() => false);
if (!deleteMsg) await message.react(success ? emojis.successFull : emojis.errorFull).catch(() => {});
diff --git a/src/commands/dev/superUser.ts b/src/commands/dev/superUser.ts
index fc7fcbf..54332d6 100644
--- a/src/commands/dev/superUser.ts
+++ b/src/commands/dev/superUser.ts
@@ -1,5 +1,5 @@
import { BotCommand, emojis, format, type ArgType, type CommandMessage } from '#lib';
-import { type ArgumentGeneratorReturn, type ArgumentTypeCasterReturn } from 'discord-akairo';
+import { type ArgumentGeneratorReturn, type ArgumentTypeCasterReturn } from '@notenoughupdates/discord-akairo';
export default class SuperUserCommand extends BotCommand {
public constructor() {
diff --git a/src/commands/dev/test.ts b/src/commands/dev/test.ts
index e1f3b73..994b76f 100644
--- a/src/commands/dev/test.ts
+++ b/src/commands/dev/test.ts
@@ -1,13 +1,14 @@
-import { BotCommand, ButtonPaginator, colors, emojis, OptArgType, Shared, type CommandMessage } from '#lib';
+import { BotCommand, ButtonPaginator, chunk, colors, emojis, OptArgType, Shared, type CommandMessage } from '#lib';
import {
ActionRowBuilder,
+ APIEmbed,
ButtonBuilder,
ButtonStyle,
+ Collection,
EmbedBuilder,
- GatewayDispatchEvents,
+ Message,
Routes,
- type ApplicationCommand,
- type Collection
+ type ApplicationCommand
} from 'discord.js';
import badLinksSecretArray from '../../../lib/badlinks-secret.js';
import badLinksArray from '../../../lib/badlinks.js';
@@ -52,15 +53,38 @@ export default class TestCommand extends BotCommand {
return await message.util.reply(responses[Math.floor(Math.random() * responses.length)]);
}
+ console.dir(args);
+
if (args.feature) {
if (['button', 'buttons'].includes(args.feature?.toLowerCase())) {
const buttonRow = new ActionRowBuilder<ButtonBuilder>().addComponents(
- new ButtonBuilder({ style: ButtonStyle.Primary, customId: 'primaryButton', label: 'Primary' }),
- new ButtonBuilder({ style: ButtonStyle.Secondary, customId: 'secondaryButton', label: 'Secondary' }),
- new ButtonBuilder({ style: ButtonStyle.Success, customId: 'successButton', label: 'Success' }),
- new ButtonBuilder({ style: ButtonStyle.Danger, customId: 'dangerButton', label: 'Danger' }),
- new ButtonBuilder({ style: ButtonStyle.Link, label: 'Link', url: 'https://www.youtube.com/watch?v=dQw4w9WgXcQ' })
+ new ButtonBuilder({
+ style: ButtonStyle.Primary,
+ customId: 'test;button;primary',
+ label: 'Primary'
+ }),
+ new ButtonBuilder({
+ style: ButtonStyle.Secondary,
+ customId: 'test;button;secondary',
+ label: 'Secondary'
+ }),
+ new ButtonBuilder({
+ style: ButtonStyle.Success,
+ customId: 'test;button;success',
+ label: 'Success'
+ }),
+ new ButtonBuilder({
+ style: ButtonStyle.Danger,
+ customId: 'test;button;danger',
+ label: 'Danger'
+ }),
+ new ButtonBuilder({
+ style: ButtonStyle.Link,
+ label: 'Link',
+ url: 'https://www.youtube.com/watch?v=dQw4w9WgXcQ'
+ })
);
+
return await message.util.reply({ content: 'buttons', components: [buttonRow] });
} else if (['embed', 'button embed'].includes(args.feature?.toLowerCase())) {
const embed = new EmbedBuilder()
@@ -80,18 +104,23 @@ export default class TestCommand extends BotCommand {
const buttonRow = new ActionRowBuilder<ButtonBuilder>().addComponents(
new ButtonBuilder({ style: ButtonStyle.Link, label: 'Link', url: 'https://google.com/' })
);
+
return await message.util.reply({ content: 'Test', embeds: [embed], components: [buttonRow] });
} else if (['lots of buttons'].includes(args.feature?.toLowerCase())) {
const buttonRows: ActionRowBuilder<ButtonBuilder>[] = [];
+
for (let a = 1; a <= 5; a++) {
const row = new ActionRowBuilder<ButtonBuilder>();
+
for (let b = 1; b <= 5; b++) {
- const id = (a + 5 * (b - 1)).toString();
+ const id = `test;lots;${a + 5 * (b - 1)}`;
const button = new ButtonBuilder({ style: ButtonStyle.Primary, customId: id, label: id });
row.addComponents(button);
}
+
buttonRows.push(row);
}
+
return await message.util.reply({ content: 'buttons', components: buttonRows });
} else if (['paginate'].includes(args.feature?.toLowerCase())) {
const embeds = [];
@@ -142,13 +171,16 @@ export default class TestCommand extends BotCommand {
return message.util.reply(`${emojis.error} no`);
} else if (['sync automod'].includes(args.feature?.toLowerCase())) {
const row = (await Shared.findByPk(0))!;
+
row.badLinks = badLinksArray;
row.badLinksSecret = badLinksSecretArray;
row.badWords = badWords;
+
await row.save();
+
return await message.util.reply(`${emojis.success} Synced automod.`);
} else if (['modal'].includes(args.feature?.toLowerCase())) {
- const m = await message.util.reply({
+ return await message.util.reply({
content: 'Click for modal',
components: [
new ActionRowBuilder<ButtonBuilder>().addComponents(
@@ -156,63 +188,57 @@ export default class TestCommand extends BotCommand {
)
]
});
+ } else if (args.feature.includes('backlog experiments')) {
+ this.client.logger.debug('backlog experiments');
+
+ if (message.channelId !== '1019830755658055691') {
+ return await message.util.reply(`${emojis.error} This only works in <#1019830755658055691>.`);
+ }
- // eslint-disable-next-line @typescript-eslint/no-misused-promises
- this.client.ws.on(GatewayDispatchEvents.InteractionCreate, async (i: any) => {
- if (i?.data?.custom_id !== 'test;modal' || i?.data?.component_type !== 2) return;
- if (i?.message?.id !== m.id) return;
-
- const text = { type: 4, style: 1, min_length: 1, max_length: 4000, required: true };
-
- await this.client.rest.post(Routes.interactionCallback(i.id, i.token), {
- body: {
- type: 9,
- data: {
- custom_id: 'test;login',
- title: 'Login (real)',
- components: [
- {
- type: 1,
- components: [
- {
- ...text,
- custom_id: 'test;login;email',
- label: 'Email',
- placeholder: 'Email'
- }
- ]
- },
- {
- type: 1,
- components: [
- {
- ...text,
- custom_id: 'test;login;password',
- label: 'Password',
- placeholder: 'Password'
- }
- ]
- },
- {
- type: 1,
- components: [
- {
- ...text,
- custom_id: 'test;login;2fa',
- label: 'Enter Discord Auth Code',
- min_length: 6,
- max_length: 6,
- placeholder: '6-digit authentication code'
- }
- ]
- }
- ]
- }
- }
+ let messages = new Collection<string, Message>();
+ let lastID: string | undefined;
+
+ // eslint-disable-next-line no-constant-condition
+ while (true) {
+ const fetchedMessages = await message.channel.messages.fetch({
+ limit: 100,
+ ...(lastID && { before: lastID })
});
- });
- return;
+ if (fetchedMessages.size === 0) {
+ break;
+ }
+
+ messages = messages.concat(fetchedMessages);
+ lastID = fetchedMessages.lastKey();
+
+ this.client.logger.debug(messages.size);
+ this.client.logger.debug(lastID);
+ }
+
+ const embeds = messages
+ .sort((a, b) => a.createdTimestamp - b.createdTimestamp)
+ .filter((m) => m.embeds.length > 0 && (m.embeds[0].title?.includes('Guild Experiment') ?? false))
+ .map(
+ (m): APIEmbed => ({
+ ...m.embeds[0]!.toJSON(),
+ timestamp: new Date(m.createdTimestamp).toISOString()
+ })
+ );
+
+ const chunked = chunk(embeds, 10);
+
+ let i = 0;
+ for (const chunk of chunked) {
+ this.client.logger.debug(i);
+ this.client.logger.debug(chunk, 1);
+ await this.client.rest.post(Routes.channelMessages('795356494261911553'), {
+ body: { embeds: chunk }
+ });
+ i++;
+ }
+
+ return await message.util.reply(`${emojis.success} Done.`);
}
}
return await message.util.reply(responses[Math.floor(Math.random() * responses.length)]);
diff --git a/src/commands/fun/minesweeper.ts b/src/commands/fun/minesweeper.ts
index 85945c7..b0528ac 100644
--- a/src/commands/fun/minesweeper.ts
+++ b/src/commands/fun/minesweeper.ts
@@ -1,8 +1,6 @@
import { BotCommand, emojis, OptArgType, type ArgType, type CommandMessage, type SlashMessage } from '#lib';
-import { Minesweeper } from '@notenoughupdates/discord.js-minesweeper';
-import assert from 'assert/strict';
+import { Minesweeper } from '@tanzanite/discord.js-minesweeper';
import { ApplicationCommandOptionType } from 'discord.js';
-assert(Minesweeper);
export default class MinesweeperCommand extends BotCommand {
public constructor() {
diff --git a/src/commands/info/guildInfo.ts b/src/commands/info/guildInfo.ts
index e364a89..acd5b86 100644
--- a/src/commands/info/guildInfo.ts
+++ b/src/commands/info/guildInfo.ts
@@ -11,6 +11,7 @@ import {
type OptArgType,
type SlashMessage
} from '#lib';
+import { embedField } from '#lib/common/tags.js';
import assert from 'assert/strict';
import {
ApplicationCommandOptionType,
@@ -26,7 +27,6 @@ import {
PermissionFlagsBits,
type BaseGuildVoiceChannel,
type GuildPreview,
- type Snowflake,
type Vanity
} from 'discord.js';
@@ -66,9 +66,13 @@ export default class GuildInfoCommand extends BotCommand {
let guild: ArgType<'guild' | 'snowflake'> | GuildPreview = args.guild ?? message.guild!;
if (typeof guild === 'string') {
- const preview = await this.client.fetchGuildPreview(`${args.guild}` as Snowflake).catch(() => undefined);
- if (preview) guild = preview;
- else return await message.util.reply(`${emojis.error} That guild is not discoverable or does not exist.`);
+ const preview = await this.client.fetchGuildPreview(`${args.guild}`).catch(() => {});
+
+ if (preview) {
+ guild = preview;
+ } else {
+ return await message.util.reply(`${emojis.error} That guild is not discoverable or does not exist.`);
+ }
}
assert(guild);
@@ -96,10 +100,13 @@ export default class GuildInfoCommand extends BotCommand {
const otherEmojis = mappings.otherEmojis;
const verifiedGuilds = Object.values(mappings.guilds);
- if (verifiedGuilds.includes(guild.id as typeof verifiedGuilds[number])) description.push(otherEmojis.BushVerified);
- if (guild instanceof Guild) {
- if (guild.premiumTier !== GuildPremiumTier.None) description.push(otherEmojis[`BoostTier${guild.premiumTier}`]);
+ if (verifiedGuilds.includes(guild.id as typeof verifiedGuilds[number])) {
+ description.push(otherEmojis.BushVerified);
+ }
+
+ if (guild instanceof Guild && guild.premiumTier !== GuildPremiumTier.None) {
+ description.push(otherEmojis[`BoostTier${guild.premiumTier}`]);
}
const features = mappings.features;
@@ -138,52 +145,65 @@ export default class GuildInfoCommand extends BotCommand {
)
] as RTCRegion[];
+ const members = guild.memberCount;
+ const online = guild.approximatePresenceCount ?? 0;
+ const offline = members - online;
+
guildAbout.push(
- `**Owner:** ${escapeMarkdown(guild.members.cache.get(guild.ownerId)?.user.tag ?? '¯\\_(ツ)_/¯')}`,
- `**Created** ${timestampAndDelta(guild.createdAt, 'd')}`,
- `**Members:** ${guild.memberCount.toLocaleString() ?? 0} (${emojis.onlineCircle} ${
- guild.approximatePresenceCount?.toLocaleString() ?? 0
- }, ${emojis.offlineCircle} ${(guild.memberCount - (guild.approximatePresenceCount ?? 0)).toLocaleString() ?? 0})`,
- `**Regions:** ${guildRegions.map((region) => mappings.regions[region] || region).join(', ')}`
+ embedField`
+ Owner ${escapeMarkdown(guild.members.cache.get(guild.ownerId)?.user.tag ?? '¯\\_(ツ)_/¯')}
+ Created ${timestampAndDelta(guild.createdAt, 'd')}
+ Members ${members} (${emojis.onlineCircle} ${online}, ${emojis.offlineCircle} ${offline})
+ Regions ${guildRegions.map((region) => mappings.regions[region] || region).join(', ')}
+ Boosts ${guild.premiumSubscriptionCount && `Level ${guild.premiumTier} with ${guild.premiumSubscriptionCount} boosts`}`
);
- if (guild.premiumSubscriptionCount)
- guildAbout.push(`**Boosts:** Level ${guild.premiumTier} with ${guild.premiumSubscriptionCount ?? 0} boosts`);
+
if (guild.members.me?.permissions.has(PermissionFlagsBits.ManageGuild) && guild.vanityURLCode) {
const vanityInfo: Vanity = await guild.fetchVanityData();
- guildAbout.push(`**Vanity URL:** discord.gg/${vanityInfo.code}`, `**Vanity Uses:** ${vanityInfo.uses?.toLocaleString()}`);
+ guildAbout.push(
+ embedField`
+ Vanity URL ${`discord.gg/${vanityInfo.code}`}
+ Vanity Uses ${vanityInfo.uses}`
+ );
}
- if (guild.icon) guildAbout.push(`**Icon:** [link](${guild.iconURL({ size: 4096, extension: 'png' })})`);
- if (guild.banner) guildAbout.push(`**Banner:** [link](${guild.bannerURL({ size: 4096, extension: 'png' })})`);
- if (guild.splash) guildAbout.push(`**Splash:** [link](${guild.splashURL({ size: 4096, extension: 'png' })})`);
+ guildAbout.push(
+ embedField`
+ Icon ${guild.icon && `[link](${guild.iconURL({ size: 4096, extension: 'png' })})`}
+ Banner ${guild.banner && `[link](${guild.bannerURL({ size: 4096, extension: 'png' })})`}
+ Splash ${guild.splash && `[link](${guild.splashURL({ size: 4096, extension: 'png' })})`}`
+ );
} else {
+ const members = guild.approximateMemberCount;
+ const online = guild.approximatePresenceCount;
+ const offline = members - online;
+
guildAbout.push(
- `**Members:** ${guild.approximateMemberCount?.toLocaleString() ?? 0} (${emojis.onlineCircle} ${
- guild.approximatePresenceCount?.toLocaleString() ?? 0
- }, ${emojis.offlineCircle} ${(
- (guild.approximateMemberCount ?? 0) - (guild.approximatePresenceCount ?? 0)
- ).toLocaleString()})`,
- `**Emojis:** ${(guild as GuildPreview).emojis.size?.toLocaleString() ?? 0}`,
- `**Stickers:** ${(guild as GuildPreview).stickers.size}`
+ embedField`
+ Members ${members} (${emojis.onlineCircle} ${online}, ${emojis.offlineCircle} ${offline})
+ Emojis ${guild.emojis.size}
+ Stickers ${guild.stickers.size}`
);
}
- embed.addFields({ name: '» About', value: guildAbout.join('\n') });
+ embed.addFields({
+ name: '» About',
+ // filter out anything that is undefined
+ value: guildAbout.filter((v) => v !== undefined).join('\n')
+ });
}
private generateStatsField(embed: EmbedBuilder, guild: Guild | GuildPreview) {
if (!(guild instanceof Guild)) return;
- const guildStats: string[] = [];
-
const channelTypes = (
[
['Text', [ChannelType.GuildText]],
['Voice', [ChannelType.GuildVoice]],
- ['News', [ChannelType.GuildNews]],
+ ['News', [ChannelType.GuildAnnouncement]],
['Stage', [ChannelType.GuildStageVoice]],
['Category', [ChannelType.GuildCategory]],
- ['Thread', [ChannelType.GuildNewsThread, ChannelType.GuildPrivateThread, ChannelType.GuildPublicThread]]
+ ['Thread', [ChannelType.AnnouncementThread, ChannelType.PrivateThread, ChannelType.PublicThread]]
] as const
).map(
(type) =>
@@ -205,30 +225,25 @@ export default class GuildInfoCommand extends BotCommand {
[GuildPremiumTier.None]: 0
} as const;
- guildStats.push(
- `**Channels:** ${guild.channels.cache.size.toLocaleString()} / 500 (${channelTypes.join(', ')})`,
- // subtract 1 for @everyone role
- `**Roles:** ${((guild.roles.cache.size ?? 0) - 1).toLocaleString()} / 250`,
- `**Emojis:** ${guild.emojis.cache.size?.toLocaleString() ?? 0} / ${EmojiTierMap[guild.premiumTier]}`,
- `**Stickers:** ${guild.stickers.cache.size?.toLocaleString() ?? 0} / ${StickerTierMap[guild.premiumTier]}`
- );
+ const guildStats = embedField`
+ Channels ${guild.channels.cache.size} / 500 (${channelTypes.join(', ')})
+ Roles ${guild.roles.cache.size - 1 /* account for @everyone role */} / 250
+ Emojis ${guild.emojis.cache.size} / ${EmojiTierMap[guild.premiumTier]}
+ Stickers ${guild.stickers.cache.size} / ${StickerTierMap[guild.premiumTier]}`;
- embed.addFields({ name: '» Stats', value: guildStats.join('\n') });
+ embed.addFields({ name: '» Stats', value: guildStats });
}
private generateSecurityField(embed: EmbedBuilder, guild: Guild | GuildPreview) {
if (!(guild instanceof Guild)) return;
- const guildSecurity: string[] = [];
-
- guildSecurity.push(
- `**Verification Level:** ${MappedGuildVerificationLevel[guild.verificationLevel]}`,
- `**Explicit Content Filter:** ${MappedGuildExplicitContentFilter[guild.explicitContentFilter]}`,
- `**Default Message Notifications:** ${MappedGuildDefaultMessageNotifications[guild.defaultMessageNotifications]}`,
- `**2FA Required:** ${guild.mfaLevel === GuildMFALevel.Elevated ? 'True' : 'False'}`
- );
+ const guildSecurity = embedField`
+ Verification Level ${MappedGuildVerificationLevel[guild.verificationLevel]}
+ Explicit Content Filter ${MappedGuildExplicitContentFilter[guild.explicitContentFilter]}
+ Default Message Notifications ${MappedGuildDefaultMessageNotifications[guild.defaultMessageNotifications]}
+ 2FA Required ${guild.mfaLevel === GuildMFALevel.Elevated ? 'True' : 'False'}`;
- embed.addFields({ name: '» Security', value: guildSecurity.join('\n') });
+ embed.addFields({ name: '» Security', value: guildSecurity });
}
}
diff --git a/src/commands/info/help.ts b/src/commands/info/help.ts
index 1680b75..565fc25 100644
--- a/src/commands/info/help.ts
+++ b/src/commands/info/help.ts
@@ -20,9 +20,11 @@ import {
ButtonStyle,
EmbedBuilder
} from 'discord.js';
-import { default as Fuse } from 'fuse.js';
import packageDotJSON from '../../../package.json' assert { type: 'json' };
+// todo: remove this bullshit once typescript gets its shit together
+const Fuse = (await import('fuse.js')).default as unknown as typeof import('fuse.js').default;
+
assert(Fuse);
assert(packageDotJSON);
diff --git a/src/commands/info/inviteInfo.ts b/src/commands/info/inviteInfo.ts
index bf66a4c..123063d 100644
--- a/src/commands/info/inviteInfo.ts
+++ b/src/commands/info/inviteInfo.ts
@@ -1,4 +1,5 @@
import { Arg, ArgType, BotCommand, colors, type CommandMessage, type SlashMessage } from '#lib';
+import { embedField } from '#lib/common/tags.js';
import { ApplicationCommandOptionType, EmbedBuilder, Invite } from 'discord.js';
export default class InviteInfoCommand extends BotCommand {
@@ -38,8 +39,10 @@ export default class InviteInfoCommand extends BotCommand {
}
private generateAboutField(embed: EmbedBuilder, invite: Invite) {
- const about = [`**code:** ${invite.code}`, `**channel:** ${invite.channel!.name}`];
+ const about = embedField`
+ Code ${invite.code}
+ Channel ${invite.channel!.name}`;
- embed.addFields({ name: '» About', value: about.join('\n') });
+ embed.addFields({ name: '» About', value: about });
}
}
diff --git a/src/commands/info/ping.ts b/src/commands/info/ping.ts
index ad58cc0..66cdf01 100644
--- a/src/commands/info/ping.ts
+++ b/src/commands/info/ping.ts
@@ -43,7 +43,7 @@ export default class PingCommand extends BotCommand {
.setColor(colors.default)
.setTimestamp();
return message.util.reply({
- content: null,
+ content: '',
embeds: [embed]
});
}
diff --git a/src/commands/info/snowflake.ts b/src/commands/info/snowflake.ts
index ba93611..1d3533e 100644
--- a/src/commands/info/snowflake.ts
+++ b/src/commands/info/snowflake.ts
@@ -1,5 +1,5 @@
import { BotCommand, colors, timestamp, type ArgType, type CommandMessage, type SlashMessage } from '#lib';
-import { stripIndent } from '#tags';
+import { embedField } from '#tags';
import {
ApplicationCommandOptionType,
ChannelType,
@@ -50,7 +50,7 @@ export default class SnowflakeCommand extends BotCommand {
snowflakeEmbed.setTitle(`:snowflake: DM with ${escapeMarkdown(channel.recipient?.tag ?? '¯\\_(ツ)_/¯')} \`[Channel]\``);
} else if (
channel.type === ChannelType.GuildCategory ||
- channel.type === ChannelType.GuildNews ||
+ channel.type === ChannelType.GuildAnnouncement ||
channel.type === ChannelType.GuildText ||
channel.type === ChannelType.GuildVoice ||
channel.type === ChannelType.GuildStageVoice ||
@@ -68,10 +68,10 @@ export default class SnowflakeCommand extends BotCommand {
// Guild
if (this.client.guilds.cache.has(snowflake)) {
const guild = this.client.guilds.cache.get(snowflake)!;
- const guildInfo = stripIndent`
- **Name:** ${escapeMarkdown(guild.name)}
- **Owner:** ${escapeMarkdown(this.client.users.cache.get(guild.ownerId)?.tag ?? '¯\\_(ツ)_/¯')} (${guild.ownerId})
- **Members:** ${guild.memberCount?.toLocaleString()}`;
+ const guildInfo = embedField`
+ Name ${escapeMarkdown(guild.name)}
+ Owner ${escapeMarkdown(this.client.users.cache.get(guild.ownerId)?.tag ?? '¯\\_(ツ)_/¯')} (${guild.ownerId})
+ Members ${guild.memberCount?.toLocaleString()}`;
if (guild.icon) snowflakeEmbed.setThumbnail(guild.iconURL({ size: 2048 })!);
snowflakeEmbed.addFields({ name: '» Server Info', value: guildInfo });
snowflakeEmbed.setTitle(`:snowflake: ${escapeMarkdown(guild.name)} \`[Server]\``);
@@ -81,8 +81,8 @@ export default class SnowflakeCommand extends BotCommand {
const fetchedUser = await this.client.users.fetch(`${snowflake}`).catch(() => undefined);
if (this.client.users.cache.has(snowflake) || fetchedUser) {
const user = (this.client.users.cache.get(snowflake) ?? fetchedUser)!;
- const userInfo = stripIndent`
- **Name:** <@${user.id}> (${escapeMarkdown(user.tag)})`;
+ const userInfo = embedField`
+ Name ${`<@${user.id}> (${escapeMarkdown(user.tag)})`}`;
if (user.avatar) snowflakeEmbed.setThumbnail(user.avatarURL({ size: 2048 })!);
snowflakeEmbed.addFields({ name: '» User Info', value: userInfo });
snowflakeEmbed.setTitle(`:snowflake: ${escapeMarkdown(user.tag)} \`[User]\``);
@@ -91,9 +91,9 @@ export default class SnowflakeCommand extends BotCommand {
// Emoji
if (this.client.emojis.cache.has(snowflake)) {
const emoji = this.client.emojis.cache.get(snowflake)!;
- const emojiInfo = stripIndent`
- **Name:** ${escapeMarkdown(emoji.name ?? '¯\\_(ツ)_/¯')}
- **Animated:** ${emoji.animated}`;
+ const emojiInfo = embedField`
+ Name ${escapeMarkdown(emoji.name ?? '¯\\_(ツ)_/¯')}
+ Animated ${emoji.animated}`;
if (emoji.url) snowflakeEmbed.setThumbnail(emoji.url);
snowflakeEmbed.addFields({ name: '» Emoji Info', value: emojiInfo });
snowflakeEmbed.setTitle(`:snowflake: ${escapeMarkdown(emoji.name ?? '¯\\_(ツ)_/¯')} \`[Emoji]\``);
@@ -102,13 +102,13 @@ export default class SnowflakeCommand extends BotCommand {
// Role
if (message.guild && message.guild.roles.cache.has(snowflake)) {
const role = message.guild.roles.cache.get(snowflake)!;
- const roleInfo = stripIndent`
- **Name:** <@&${role.id}> (${escapeMarkdown(role.name)})
- **Members:** ${role.members.size}
- **Hoisted:** ${role.hoist}
- **Managed:** ${role.managed}
- **Position:** ${role.position}
- **Hex Color:** ${role.hexColor}`;
+ const roleInfo = embedField`
+ Name ${`<@&${role.id}> (${escapeMarkdown(role.name)})`}
+ Members ${role.members.size}
+ Hoisted ${role.hoist}
+ Managed ${role.managed}
+ Position ${role.position}
+ Hex Color ${role.hexColor}`;
if (role.color) snowflakeEmbed.setColor(role.color);
snowflakeEmbed.addFields({ name: '» Role Info', value: roleInfo });
snowflakeEmbed.setTitle(`:snowflake: ${escapeMarkdown(role.name)} \`[Role]\``);
@@ -116,12 +116,12 @@ export default class SnowflakeCommand extends BotCommand {
// SnowflakeInfo
const deconstructedSnowflake: DeconstructedSnowflake = SnowflakeUtil.deconstruct(snowflake);
- const snowflakeInfo = stripIndent`
- **Timestamp:** ${deconstructedSnowflake.timestamp}
- **Created:** ${timestamp(new Date(Number(deconstructedSnowflake.timestamp)))}
- **Worker ID:** ${deconstructedSnowflake.workerId}
- **Process ID:** ${deconstructedSnowflake.processId}
- **Increment:** ${deconstructedSnowflake.increment}`;
+ const snowflakeInfo = embedField`
+ Timestamp ${deconstructedSnowflake.timestamp}
+ Created ${timestamp(new Date(Number(deconstructedSnowflake.timestamp)))}
+ Worker ID ${deconstructedSnowflake.workerId}
+ Process ID ${deconstructedSnowflake.processId}
+ Increment ${deconstructedSnowflake.increment}`;
snowflakeEmbed.addFields({ name: '» Snowflake Info', value: snowflakeInfo });
return await message.util.reply({ embeds: [snowflakeEmbed] });
diff --git a/src/commands/info/userInfo.ts b/src/commands/info/userInfo.ts
index 25621fa..22088fe 100644
--- a/src/commands/info/userInfo.ts
+++ b/src/commands/info/userInfo.ts
@@ -13,6 +13,7 @@ import {
type OptArgType,
type SlashMessage
} from '#lib';
+import { embedField } from '#lib/common/tags.js';
import {
ActivityType,
ApplicationCommandOptionType,
@@ -20,7 +21,6 @@ import {
EmbedBuilder,
escapeMarkdown,
PermissionFlagsBits,
- TeamMemberMembershipState,
UserFlags,
type APIApplication,
type ApplicationFlagsString,
@@ -128,62 +128,69 @@ export default class UserInfoCommand extends BotCommand {
await this.generateBotField(userEmbed, user);
- if (emojis)
+ if (emojis) {
userEmbed.setDescription(
`\u200B${emojis.filter((e) => e).join(' ')}${
userEmbed.data.description?.length ? `\n\n${userEmbed.data.description}` : ''
}`
); // zero width space
+ }
+
return userEmbed;
}
public static async generateGeneralInfoField(embed: EmbedBuilder, user: User, title = '» General Information') {
- // General Info
- const generalInfo = [
- `**Mention:** <@${user.id}>`,
- `**ID:** ${user.id}`,
- `**Created:** ${timestampAndDelta(user.createdAt, 'd')}`
- ];
- if (user.accentColor !== null) generalInfo.push(`**Accent Color:** ${user.hexAccentColor}`);
- if (user.banner) generalInfo.push(`**Banner:** [link](${user.bannerURL({ extension: 'png', size: 4096 })})`);
-
- const pronouns = await Promise.race([user.client.utils.getPronounsOf(user), sleep(2 * Time.Second)]); // cut off request after 2 seconds
-
- if (pronouns && typeof pronouns === 'string' && pronouns !== 'Unspecified') generalInfo.push(`**Pronouns:** ${pronouns}`);
-
- embed.addFields({ name: title, value: generalInfo.join('\n') });
+ const pronouns = await Promise.race([
+ user.client.utils.getPronounsOf(user),
+ // cut off request after 2 seconds
+ sleep(2 * Time.Second)
+ ]);
+
+ const generalInfo = embedField`
+ Mention ${`<@${user.id}>`}
+ ID ${user.id}
+ Created ${timestampAndDelta(user.createdAt, 'd')}
+ Accent Color ${user.hexAccentColor}
+ Banner ${user.banner && `[link](${user.bannerURL({ extension: 'png', size: 4096 })})`}
+ Pronouns ${typeof pronouns === 'string' && pronouns !== 'Unspecified' && pronouns}`;
+
+ embed.addFields({ name: title, value: generalInfo });
}
public static generateServerInfoField(embed: EmbedBuilder, member?: GuildMember | undefined, title = '» Server Information') {
if (!member) return;
- // Server User Info
- const serverUserInfo = [];
- if (member.joinedTimestamp)
- serverUserInfo.push(
- `**${member.guild!.ownerId == member.user.id ? 'Created Server' : 'Joined'}:** ${timestampAndDelta(
- member.joinedAt!,
- 'd'
- )}`
- );
- if (member.premiumSince) serverUserInfo.push(`**Booster Since:** ${timestampAndDelta(member.premiumSince, 'd')}`);
- if (member.displayHexColor) serverUserInfo.push(`**Display Color:** ${member.displayHexColor}`);
- if (member.user.id == mappings.users['IRONM00N'] && member.guild?.id == mappings.guilds["Moulberry's Bush"])
- serverUserInfo.push(`**General Deletions:** 1⅓`);
- if (
- ([mappings.users['nopo'], mappings.users['Bestower']] as const).includes(member.user.id) &&
- member.guild.id == mappings.guilds["Moulberry's Bush"]
- )
- serverUserInfo.push(`**General Deletions:** ⅓`);
- if (member?.nickname) serverUserInfo.push(`**Nickname:** ${escapeMarkdown(member?.nickname)}`);
- if (serverUserInfo.length) embed.addFields({ name: title, value: serverUserInfo.join('\n') });
+ const isGuildOwner = member.guild.ownerId === member.id;
+
+ const deletions = (() => {
+ if (member.guild.id !== mappings.guilds["Moulberry's Bush"]) return null;
+
+ switch (member.id) {
+ case mappings.users['IRONM00N']:
+ return '1⅓';
+ case mappings.users['nopo']:
+ case mappings.users['Bestower']:
+ return '⅓';
+ default:
+ return null;
+ }
+ })();
+
+ const serverUserInfo = embedField`
+ Created Server ${member.joinedAt && isGuildOwner && timestampAndDelta(member.joinedAt!, 'd')}
+ Joined ${member.joinedAt && !isGuildOwner && timestampAndDelta(member.joinedAt!, 'd')}
+ Booster Since ${member.premiumSince && timestampAndDelta(member.premiumSince, 'd')}
+ Display Color ${member.displayHexColor}
+ #general Deletions ${deletions}
+ Nickname ${member.nickname && escapeMarkdown(member.nickname)}`;
+
+ if (serverUserInfo.length) embed.addFields({ name: title, value: serverUserInfo });
}
public static generatePresenceField(embed: EmbedBuilder, member?: GuildMember | undefined, title = '» Presence') {
if (!member || !member.presence) return;
if (!member.presence.status && !member.presence.clientStatus && !member.presence.activities) return;
- // User Presence Info
let customStatus = '';
const activitiesNames: string[] = [];
if (member.presence.activities) {
@@ -231,7 +238,7 @@ export default class UserInfoCommand extends BotCommand {
const joined = roles.join(', ');
embed.addFields({
name: `» Role${roles.length - 1 ? 's' : ''} [${roles.length}]`,
- value: joined.length > 1024 ? 'Too Many Roles to Display' + '...' : joined
+ value: joined.length > 1024 ? 'Too Many Roles to Display...' : joined
});
}
@@ -242,7 +249,6 @@ export default class UserInfoCommand extends BotCommand {
) {
if (!member) return;
- // Important Perms
const perms = this.getImportantPermissions(member);
if (perms.length) embed.addFields({ name: title, value: perms.join(' ') });
@@ -282,27 +288,13 @@ export default class UserInfoCommand extends BotCommand {
return emojis.cross;
};
- const botInfo = [
- `**Publicity:** ${applicationInfo.bot_public ? 'Public' : 'Private'}`,
- `**Requires Code Grant:** ${applicationInfo.bot_require_code_grant ? emojis.check : emojis.cross}`,
- `**Server Members Intent:** ${intent('GatewayGuildMembers', 'GatewayGuildMembersLimited')}`,
- `**Presence Intent:** ${intent('GatewayPresence', 'GatewayPresenceLimited')}`,
- `**Message Content Intent:** ${intent('GatewayMessageContent', 'GatewayMessageContentLimited')}`
- ];
-
- if (applicationInfo.owner || applicationInfo.team) {
- const teamMembers = applicationInfo.owner
- ? [applicationInfo.owner]
- : applicationInfo
- .team!.members.filter((tm) => tm.membership_state === TeamMemberMembershipState.Accepted)
- .map((tm) => tm.user);
- botInfo.push(
- `**Developer${teamMembers.length > 1 ? 's' : ''}:** ${teamMembers
- .map((m) => `${m.username}#${m.discriminator}`)
- .join(', ')}`
- );
- }
+ const botInfo = embedField`
+ Publicity ${applicationInfo.bot_public ? 'Public' : 'Private'}
+ Code Grant ${applicationInfo.bot_require_code_grant ? 'Required' : 'Not Required'}
+ Server Members Intent ${intent('GatewayGuildMembers', 'GatewayGuildMembersLimited')}
+ Presence Intent ${intent('GatewayPresence', 'GatewayPresenceLimited')}
+ Message Content Intent ${intent('GatewayMessageContent', 'GatewayMessageContentLimited')}`;
- if (botInfo.length) embed.addFields({ name: title, value: botInfo.join('\n') });
+ embed.addFields({ name: title, value: botInfo });
}
}
diff --git a/src/commands/leveling/level.ts b/src/commands/leveling/level.ts
index 869140d..bf4ca9b 100644
--- a/src/commands/leveling/level.ts
+++ b/src/commands/leveling/level.ts
@@ -9,11 +9,11 @@ import {
type SlashMessage
} from '#lib';
import canvas from '@napi-rs/canvas';
-import { SimplifyNumber } from '@notenoughupdates/simplify-number';
+import { simplifyNumber } from '@tanzanite/simplify-number';
import assert from 'assert/strict';
import { ApplicationCommandOptionType, AttachmentBuilder, Guild, PermissionFlagsBits, User } from 'discord.js';
+
assert(canvas);
-assert(SimplifyNumber);
export default class LevelCommand extends BotCommand {
public constructor() {
@@ -119,9 +119,9 @@ export default class LevelCommand extends BotCommand {
// Draw level data text
ctx.fillStyle = white;
- const xpTxt = `${SimplifyNumber(currentLevelXpProgress)}/${SimplifyNumber(xpForNextLevel)}`;
+ const xpTxt = `${simplifyNumber(currentLevelXpProgress)}/${simplifyNumber(xpForNextLevel)}`;
- const rankTxt = SimplifyNumber(rank.indexOf(rank.find((x) => x.user === user.id)!) + 1);
+ const rankTxt = simplifyNumber(rank.indexOf(rank.find((x) => x.user === user.id)!) + 1);
ctx.fillText(`Level: ${userLevel} XP: ${xpTxt} Rank: ${rankTxt}`, AVATAR_SIZE + 70, AVATAR_SIZE - 20);
// Return image in buffer form
diff --git a/src/commands/leveling/setLevel.ts b/src/commands/leveling/setLevel.ts
index 6f6f69e..3a995a2 100644
--- a/src/commands/leveling/setLevel.ts
+++ b/src/commands/leveling/setLevel.ts
@@ -1,4 +1,5 @@
-import { AllowedMentions, BotCommand, emojis, format, Level, type ArgType, type CommandMessage, type SlashMessage } from '#lib';
+import { AllowedMentions, BotCommand, emojis, Level, type ArgType, type CommandMessage, type SlashMessage } from '#lib';
+import { commas } from '#lib/common/tags.js';
import assert from 'assert/strict';
import { ApplicationCommandOptionType } from 'discord.js';
@@ -42,20 +43,27 @@ export default class SetLevelCommand extends BotCommand {
assert(message.inGuild());
assert(user.id);
- if (isNaN(level) || !Number.isInteger(level))
+ if (isNaN(level) || !Number.isInteger(level)) {
return await message.util.reply(`${emojis.error} Provide a valid number to set the user's level to.`);
- if (level > 6553 || level < 0)
- return await message.util.reply(`${emojis.error} You cannot set a level higher than **6,553**.`);
+ }
+
+ if (level > Level.MAX_LEVEL || level < 0) {
+ return await message.util.reply(commas`${emojis.error} You cannot set a level higher than **${Level.MAX_LEVEL}**.`);
+ }
const [levelEntry] = await Level.findOrBuild({
- where: { user: user.id, guild: message.guild.id },
- defaults: { user: user.id, guild: message.guild.id, xp: 0 }
+ where: {
+ user: user.id,
+ guild: message.guild.id
+ }
});
- await levelEntry.update({ xp: Level.convertLevelToXp(level), user: user.id, guild: message.guild.id });
+
+ const xp = Level.convertLevelToXp(level);
+
+ await levelEntry.update({ xp, user: user.id, guild: message.guild.id });
+
return await message.util.send({
- content: `Successfully set level of <@${user.id}> to ${format.input(level.toLocaleString())} (${format.input(
- levelEntry.xp.toLocaleString()
- )} XP)`,
+ content: commas`Successfully set level of <@${user.id}> to **${level}** (**${xp}** xp)`,
allowedMentions: AllowedMentions.none()
});
}
diff --git a/src/commands/leveling/setXp.ts b/src/commands/leveling/setXp.ts
index 8c3b86f..270ad68 100644
--- a/src/commands/leveling/setXp.ts
+++ b/src/commands/leveling/setXp.ts
@@ -1,4 +1,6 @@
-import { AllowedMentions, BotCommand, emojis, format, Level, type ArgType, type CommandMessage, type SlashMessage } from '#lib';
+import { AllowedMentions, BotCommand, emojis, Level, type ArgType, type CommandMessage, type SlashMessage } from '#lib';
+import { commas } from '#lib/common/tags.js';
+import { input } from '#lib/utils/Format.js';
import assert from 'assert/strict';
import { ApplicationCommandOptionType } from 'discord.js';
@@ -44,22 +46,36 @@ export default class SetXpCommand extends BotCommand {
assert(user.id);
if (isNaN(xp)) return await message.util.reply(`${emojis.error} Provide a valid number.`);
- if (xp > 2147483647 || xp < 0)
+
+ if (xp > Level.MAX_XP || xp < 0) {
return await message.util.reply(
- `${emojis.error} Provide an positive integer under **2,147,483,647** to set the user's xp to.`
+ commas`${emojis.error} Provide an positive integer under **${Level.MAX_XP}** to set the user's xp to.`
);
+ }
const [levelEntry] = await Level.findOrBuild({
- where: { user: user.id, guild: message.guild.id },
- defaults: { user: user.id, guild: message.guild.id }
+ where: {
+ user: user.id,
+ guild: message.guild.id
+ }
});
- await levelEntry.update({ xp: xp, user: user.id, guild: message.guild.id });
+ const res = await levelEntry
+ .update({ xp: xp, user: user.id, guild: message.guild.id })
+ .catch((e) => (e instanceof Error ? e : null));
+
+ xp = levelEntry.xp;
+ const level = Level.convertXpToLevel(xp);
+
+ if (res instanceof Error || res == null) {
+ return await message.util.reply({
+ content: commas`Unable to set <@${user.id}>'s xp to **${xp}** with error ${input(res?.message ?? '¯\\_(ツ)_/¯')}.`,
+ allowedMentions: AllowedMentions.none()
+ });
+ }
return await message.util.send({
- content: `Successfully set <@${user.id}>'s xp to ${format.input(levelEntry.xp.toLocaleString())} (level ${format.input(
- Level.convertXpToLevel(levelEntry.xp).toLocaleString()
- )}).`,
+ content: commas`${emojis.success} Successfully set <@${user.id}>'s xp to **${xp}** (level **${level}**).`,
allowedMentions: AllowedMentions.none()
});
}
diff --git a/src/commands/moderation/ban.ts b/src/commands/moderation/ban.ts
index aee8805..ae77cde 100644
--- a/src/commands/moderation/ban.ts
+++ b/src/commands/moderation/ban.ts
@@ -96,7 +96,9 @@ export default class BanCommand extends BotCommand {
if (!user) return message.util.reply(`${emojis.error} Invalid user.`);
const useForce = args.force && message.author.isOwner();
- const canModerateResponse = member ? await Moderation.permissionCheck(message.member, member, 'ban', true, useForce) : true;
+ const canModerateResponse = member
+ ? await Moderation.permissionCheck(message.member, member, Moderation.Action.Ban, true, useForce)
+ : true;
if (canModerateResponse !== true) {
return await message.util.reply(canModerateResponse);
diff --git a/src/commands/moderation/block.ts b/src/commands/moderation/block.ts
index a5ad31d..da1dec8 100644
--- a/src/commands/moderation/block.ts
+++ b/src/commands/moderation/block.ts
@@ -83,7 +83,7 @@ export default class BlockCommand extends BotCommand {
return await message.util.reply(`${emojis.error} The user you selected is not in the server or is not a valid user.`);
const useForce = args.force && message.author.isOwner();
- const canModerateResponse = await Moderation.permissionCheck(message.member, member, 'block', true, useForce);
+ const canModerateResponse = await Moderation.permissionCheck(message.member, member, Moderation.Action.Block, true, useForce);
if (canModerateResponse !== true) {
return message.util.reply(canModerateResponse);
diff --git a/src/commands/moderation/evidence.ts b/src/commands/moderation/evidence.ts
index 9a5e70f..b7c020a 100644
--- a/src/commands/moderation/evidence.ts
+++ b/src/commands/moderation/evidence.ts
@@ -10,8 +10,8 @@ import {
type CommandMessage,
type SlashMessage
} from '#lib';
+import { Argument, ArgumentGeneratorReturn } from '@notenoughupdates/discord-akairo';
import assert from 'assert/strict';
-import { Argument, ArgumentGeneratorReturn } from 'discord-akairo';
import { ApplicationCommandOptionType, type Message } from 'discord.js';
export default class EvidenceCommand extends BotCommand {
diff --git a/src/commands/moderation/kick.ts b/src/commands/moderation/kick.ts
index 82ddce4..d757e91 100644
--- a/src/commands/moderation/kick.ts
+++ b/src/commands/moderation/kick.ts
@@ -70,7 +70,7 @@ export default class KickCommand extends BotCommand {
if (!member)
return await message.util.reply(`${emojis.error} The user you selected is not in the server or is not a valid user.`);
const useForce = force && message.author.isOwner();
- const canModerateResponse = await Moderation.permissionCheck(message.member, member, 'kick', true, useForce);
+ const canModerateResponse = await Moderation.permissionCheck(message.member, member, Moderation.Action.Kick, true, useForce);
if (canModerateResponse !== true) {
return message.util.reply(canModerateResponse);
diff --git a/src/commands/moderation/modlog.ts b/src/commands/moderation/modlog.ts
index dcab9ef..649e44f 100644
--- a/src/commands/moderation/modlog.ts
+++ b/src/commands/moderation/modlog.ts
@@ -12,12 +12,11 @@ import {
type CommandMessage,
type SlashMessage
} from '#lib';
+import { embedField } from '#lib/common/tags.js';
import assert from 'assert/strict';
import { ApplicationCommandOptionType, escapeMarkdown, User } from 'discord.js';
export default class ModlogCommand extends BotCommand {
- public static separator = '\n━━━━━━━━━━━━━━━\n';
-
public constructor() {
super('modlog', {
aliases: ['modlog', 'modlogs'],
@@ -62,44 +61,63 @@ export default class ModlogCommand extends BotCommand {
const logs = await ModLog.findAll({
where: {
guild: message.guild.id,
- user: foundUser.id
+ user: foundUser.id,
+ pseudo: false
},
order: [['createdAt', 'ASC']]
});
- const niceLogs = logs
- .filter((log) => !log.pseudo && !(!hidden && log.hidden))
- .map((log) => ModlogCommand.generateModlogInfo(log, false, false));
- if (niceLogs.length < 1) return message.util.reply(`${emojis.error} **${foundUser.tag}** does not have any modlogs.`);
+ const niceLogs = logs.filter((log) => !log.hidden || hidden).map((log) => generateModlogInfo(log, false, false));
+
+ if (niceLogs.length < 1) {
+ return message.util.reply(`${emojis.error} **${foundUser.tag}** does not have any modlogs.`);
+ }
+
const chunked: string[][] = chunk(niceLogs, 4);
const embedPages = chunked.map((chunk) => ({
title: `${foundUser.tag}'s Modlogs`,
- description: chunk.join(ModlogCommand.separator),
+ description: chunk.join(modlogSeparator),
color: colors.default
}));
return await ButtonPaginator.send(message, embedPages, undefined, true);
} else if (search) {
const entry = await ModLog.findByPk(search as string);
- if (!entry || entry.pseudo || (entry.hidden && !hidden))
+
+ if (!entry || entry.pseudo || (entry.hidden && !hidden)) {
return message.util.send(`${emojis.error} That modlog does not exist.`);
- if (entry.guild !== message.guild.id) return message.util.reply(`${emojis.error} This modlog is from another server.`);
+ }
+
+ if (entry.guild !== message.guild.id) {
+ return message.util.reply(`${emojis.error} This modlog is from another server.`);
+ }
+
const embed = {
title: `Case ${entry.id}`,
- description: ModlogCommand.generateModlogInfo(entry, true, false),
+ description: generateModlogInfo(entry, true, false),
color: colors.default
};
return await ButtonPaginator.send(message, [embed]);
}
}
+}
- public static generateModlogInfo(log: ModLog, showUser: boolean, userFacing: boolean): string {
- const trim = (str: string): string => (str.endsWith('\n') ? str.substring(0, str.length - 1).trim() : str.trim());
- const modLog = [`**Case ID:** ${escapeMarkdown(log.id)}`, `**Type:** ${log.type.toLowerCase()}`];
- if (showUser) modLog.push(`**User:** <@!${log.user}>`);
- if (!userFacing) modLog.push(`**Moderator:** <@!${log.moderator}>`);
- if (log.duration) modLog.push(`**Duration:** ${humanizeDuration(log.duration)}`);
- modLog.push(`**Reason:** ${trim(log.reason ?? 'No Reason Specified.')}`);
- modLog.push(`**Date:** ${timestamp(log.createdAt)}`);
- if (log.evidence && !userFacing) modLog.push(`**Evidence:** ${trim(log.evidence)}`);
- return modLog.join(`\n`);
+export const modlogSeparator = '\n━━━━━━━━━━━━━━━\n';
+
+const trim = (str: string): string => {
+ if (str.endsWith('\n')) {
+ return str.substring(0, str.length - 1).trim();
+ } else {
+ return str.trim();
}
+};
+
+export function generateModlogInfo(log: ModLog, showUser: boolean, userFacing: boolean): string {
+ return embedField`
+ Case ID ${escapeMarkdown(log.id)}
+ Type ${log.type.toLowerCase()}
+ User ${showUser && `<@!${log.user}>`}
+ Moderator ${!userFacing && `<@!${log.moderator}>`}
+ Duration ${log.duration && humanizeDuration(log.duration)}
+ Reason ${trim(log.reason ?? 'No Reason Specified.')}
+ Date ${timestamp(log.createdAt)}
+ Evidence ${log.evidence && !userFacing && trim(log.evidence)}`;
}
diff --git a/src/commands/moderation/mute.ts b/src/commands/moderation/mute.ts
index 9ffaf8d..a64dc99 100644
--- a/src/commands/moderation/mute.ts
+++ b/src/commands/moderation/mute.ts
@@ -78,7 +78,7 @@ export default class MuteCommand extends BotCommand {
return await message.util.reply(`${emojis.error} The user you selected is not in the server or is not a valid user.`);
const useForce = args.force && message.author.isOwner();
- const canModerateResponse = await Moderation.permissionCheck(message.member, member, 'mute', true, useForce);
+ const canModerateResponse = await Moderation.permissionCheck(message.member, member, Moderation.Action.Mute, true, useForce);
if (canModerateResponse !== true) {
return message.util.reply(canModerateResponse);
diff --git a/src/commands/moderation/myLogs.ts b/src/commands/moderation/myLogs.ts
index 8faca8c..e3f5f10 100644
--- a/src/commands/moderation/myLogs.ts
+++ b/src/commands/moderation/myLogs.ts
@@ -12,7 +12,7 @@ import {
import { ApplicationCommandOptionType } from 'discord.js';
import { input, sanitizeInputForDiscord } from '../../../lib/utils/Format.js';
-import ModlogCommand from './modlog.js';
+import { generateModlogInfo, modlogSeparator } from './modlog.js';
export default class MyLogsCommand extends BotCommand {
public constructor() {
super('myLogs', {
@@ -50,14 +50,14 @@ export default class MyLogsCommand extends BotCommand {
const logs = await ModLog.findAll({
where: {
guild: guild.id,
- user: message.author.id
+ user: message.author.id,
+ pseudo: false,
+ hidden: false
},
order: [['createdAt', 'ASC']]
});
- const niceLogs = logs
- .filter((log) => !log.pseudo && !log.hidden)
- .map((log) => ModlogCommand.generateModlogInfo(log, false, true));
+ const niceLogs = logs.map((log) => generateModlogInfo(log, false, true));
if (niceLogs.length < 1) return message.util.reply(`${emojis.error} You don't have any modlogs in ${input(guild.name)}.`);
@@ -65,7 +65,7 @@ export default class MyLogsCommand extends BotCommand {
const embedPages = chunked.map((chunk) => ({
title: `Your Modlogs in ${sanitizeInputForDiscord(guild.name)}`,
- description: chunk.join(ModlogCommand.separator),
+ description: chunk.join(modlogSeparator),
color: colors.default
}));
diff --git a/src/commands/moderation/role.ts b/src/commands/moderation/role.ts
index 565f214..a664aa4 100644
--- a/src/commands/moderation/role.ts
+++ b/src/commands/moderation/role.ts
@@ -12,8 +12,8 @@ import {
type OptArgType,
type SlashMessage
} from '#lib';
+import { type ArgumentGeneratorReturn } from '@notenoughupdates/discord-akairo';
import assert from 'assert/strict';
-import { type ArgumentGeneratorReturn } from 'discord-akairo';
import { ApplicationCommandOptionType, PermissionFlagsBits, type Snowflake } from 'discord.js';
export default class RoleCommand extends BotCommand {
diff --git a/src/commands/moderation/slowmode.ts b/src/commands/moderation/slowmode.ts
index 82d0264..1256d1f 100644
--- a/src/commands/moderation/slowmode.ts
+++ b/src/commands/moderation/slowmode.ts
@@ -1,6 +1,6 @@
import { Arg, BotCommand, emojis, format, humanizeDuration, type CommandMessage, type OptArgType, type SlashMessage } from '#lib';
+import { Argument } from '@notenoughupdates/discord-akairo';
import assert from 'assert/strict';
-import { Argument } from 'discord-akairo';
import { ApplicationCommandOptionType, ChannelType } from 'discord.js';
export default class SlowmodeCommand extends BotCommand {
@@ -30,7 +30,7 @@ export default class SlowmodeCommand extends BotCommand {
retry: '{error} Choose a valid channel.',
optional: true,
slashType: ApplicationCommandOptionType.Channel,
- channelTypes: [ChannelType.GuildText, ChannelType.GuildPrivateThread, ChannelType.GuildPublicThread]
+ channelTypes: [ChannelType.GuildText, ChannelType.PrivateThread, ChannelType.PublicThread]
}
],
slash: true,
@@ -55,7 +55,7 @@ export default class SlowmodeCommand extends BotCommand {
if (
args.channel.type !== ChannelType.GuildText &&
- args.channel.type !== ChannelType.GuildNews &&
+ args.channel.type !== ChannelType.GuildAnnouncement &&
args.channel.type !== ChannelType.GuildVoice &&
!args.channel.isThread()
)
diff --git a/src/commands/moderation/timeout.ts b/src/commands/moderation/timeout.ts
index 7bb02f7..db6ab56 100644
--- a/src/commands/moderation/timeout.ts
+++ b/src/commands/moderation/timeout.ts
@@ -73,7 +73,13 @@ export default class TimeoutCommand extends BotCommand {
return await message.util.reply(`${emojis.error} The user you selected is not in the server or is not a valid user.`);
const useForce = args.force && message.author.isOwner();
- const canModerateResponse = await Moderation.permissionCheck(message.member, member, 'timeout', true, useForce);
+ const canModerateResponse = await Moderation.permissionCheck(
+ message.member,
+ member,
+ Moderation.Action.Timeout,
+ true,
+ useForce
+ );
if (canModerateResponse !== true) {
return message.util.reply(canModerateResponse);
diff --git a/src/commands/moderation/unblock.ts b/src/commands/moderation/unblock.ts
index 4838392..4fdfc28 100644
--- a/src/commands/moderation/unblock.ts
+++ b/src/commands/moderation/unblock.ts
@@ -75,7 +75,13 @@ export default class UnblockCommand extends BotCommand {
return await message.util.reply(`${emojis.error} The user you selected is not in the server or is not a valid user.`);
const useForce = args.force && message.author.isOwner();
- const canModerateResponse = await Moderation.permissionCheck(message.member, member, 'unblock', true, useForce);
+ const canModerateResponse = await Moderation.permissionCheck(
+ message.member,
+ member,
+ Moderation.Action.Unblock,
+ true,
+ useForce
+ );
if (canModerateResponse !== true) {
return message.util.reply(canModerateResponse);
diff --git a/src/commands/moderation/unmute.ts b/src/commands/moderation/unmute.ts
index a4d348d..c8fccc8 100644
--- a/src/commands/moderation/unmute.ts
+++ b/src/commands/moderation/unmute.ts
@@ -66,7 +66,13 @@ export default class UnmuteCommand extends BotCommand {
const member = message.guild.members.cache.get(user.id)!;
const useForce = force && message.author.isOwner();
- const canModerateResponse = await Moderation.permissionCheck(message.member, member, 'unmute', true, useForce);
+ const canModerateResponse = await Moderation.permissionCheck(
+ message.member,
+ member,
+ Moderation.Action.Unmute,
+ true,
+ useForce
+ );
if (canModerateResponse !== true) {
return message.util.reply(canModerateResponse);
diff --git a/src/commands/moderation/untimeout.ts b/src/commands/moderation/untimeout.ts
index 3775c65..64364e5 100644
--- a/src/commands/moderation/untimeout.ts
+++ b/src/commands/moderation/untimeout.ts
@@ -73,7 +73,13 @@ export default class UntimeoutCommand extends BotCommand {
if (!member.isCommunicationDisabled()) return message.util.reply(`${emojis.error} That user is not timed out.`);
const useForce = args.force && message.author.isOwner();
- const canModerateResponse = await Moderation.permissionCheck(message.member, member, 'timeout', true, useForce);
+ const canModerateResponse = await Moderation.permissionCheck(
+ message.member,
+ member,
+ Moderation.Action.Untimeout,
+ true,
+ useForce
+ );
if (canModerateResponse !== true) {
return message.util.reply(canModerateResponse);
diff --git a/src/commands/moderation/warn.ts b/src/commands/moderation/warn.ts
index 4bc7f13..a7ed814 100644
--- a/src/commands/moderation/warn.ts
+++ b/src/commands/moderation/warn.ts
@@ -69,7 +69,7 @@ export default class WarnCommand extends BotCommand {
const member = message.guild.members.cache.get(user.id);
if (!member) return message.util.reply(`${emojis.error} I cannot warn users that are not in the server.`);
const useForce = force && message.author.isOwner();
- const canModerateResponse = await Moderation.permissionCheck(message.member, member, 'warn', true, useForce);
+ const canModerateResponse = await Moderation.permissionCheck(message.member, member, Moderation.Action.Warn, true, useForce);
if (canModerateResponse !== true) {
return message.util.reply(canModerateResponse);
diff --git a/src/commands/moulberry-bush/capes.ts b/src/commands/moulberry-bush/capes.ts
index b292f24..a67cf46 100644
--- a/src/commands/moulberry-bush/capes.ts
+++ b/src/commands/moulberry-bush/capes.ts
@@ -13,7 +13,9 @@ import {
} from '#lib';
import assert from 'assert/strict';
import { ApplicationCommandOptionType, type APIEmbed, type AutocompleteInteraction } from 'discord.js';
-import { default as Fuse } from 'fuse.js';
+
+// todo: remove this bullshit once typescript gets its shit together
+const Fuse = (await import('fuse.js')).default as unknown as typeof import('fuse.js').default;
assert(Fuse);
@@ -85,7 +87,7 @@ export default class CapesCommand extends BotCommand {
}
} else {
const embeds: APIEmbed[] = capes.map(this.makeEmbed);
- await ButtonPaginator.send(message, embeds, null);
+ await ButtonPaginator.send(message, embeds, '');
}
}
diff --git a/src/commands/tickets/ticket-!.ts b/src/commands/tickets/ticket-!.ts
index c5c59f2..b98ec1f 100644
--- a/src/commands/tickets/ticket-!.ts
+++ b/src/commands/tickets/ticket-!.ts
@@ -1,5 +1,5 @@
import { BotCommand, deepWriteable, type SlashMessage } from '#lib';
-import { Flag, type ArgumentGeneratorReturn, type SlashOption } from 'discord-akairo';
+import { Flag, type ArgumentGeneratorReturn, type SlashOption } from '@notenoughupdates/discord-akairo';
import { ApplicationCommandOptionType } from 'discord.js';
export const ticketSubcommands = deepWriteable({
diff --git a/src/commands/utilities/activity.ts b/src/commands/utilities/activity.ts
index 89ca53e..3f17d0a 100644
--- a/src/commands/utilities/activity.ts
+++ b/src/commands/utilities/activity.ts
@@ -7,7 +7,7 @@ import {
type CommandMessage,
type SlashMessage
} from '#lib';
-import { type ArgumentGeneratorReturn, type ArgumentTypeCaster } from 'discord-akairo';
+import { type ArgumentGeneratorReturn, type ArgumentTypeCaster } from '@notenoughupdates/discord-akairo';
import { ApplicationCommandOptionType, ChannelType, type DiscordAPIError, type Snowflake } from 'discord.js';
const activityMap = {
diff --git a/src/commands/utilities/highlight-!.ts b/src/commands/utilities/highlight-!.ts
index 7716887..0e2db33 100644
--- a/src/commands/utilities/highlight-!.ts
+++ b/src/commands/utilities/highlight-!.ts
@@ -1,5 +1,5 @@
import { BotCommand, deepWriteable, Highlight, HighlightWord, type SlashMessage } from '#lib';
-import { Flag, type ArgumentGeneratorReturn, type SlashOption } from 'discord-akairo';
+import { Flag, type ArgumentGeneratorReturn, type SlashOption } from '@notenoughupdates/discord-akairo';
import { ApplicationCommandOptionType, Constants, type AutocompleteInteraction, type CacheType } from 'discord.js';
export const highlightSubcommands = deepWriteable({
diff --git a/src/commands/utilities/highlight-block.ts b/src/commands/utilities/highlight-block.ts
index b16852e..d1dec1e 100644
--- a/src/commands/utilities/highlight-block.ts
+++ b/src/commands/utilities/highlight-block.ts
@@ -1,6 +1,6 @@
import { AllowedMentions, BotCommand, emojis, type ArgType, type CommandMessage, type SlashMessage } from '#lib';
+import { Argument, ArgumentGeneratorReturn } from '@notenoughupdates/discord-akairo';
import assert from 'assert/strict';
-import { Argument, ArgumentGeneratorReturn } from 'discord-akairo';
import { BaseChannel, GuildMember, User } from 'discord.js';
import { HighlightBlockResult } from '../../../lib/common/HighlightManager.js';
import { highlightSubcommands } from './highlight-!.js';
diff --git a/src/commands/utilities/highlight-matches.ts b/src/commands/utilities/highlight-matches.ts
index d54fd4a..0665b37 100644
--- a/src/commands/utilities/highlight-matches.ts
+++ b/src/commands/utilities/highlight-matches.ts
@@ -1,6 +1,6 @@
import { BotCommand, ButtonPaginator, chunk, colors, emojis, type ArgType, type CommandMessage, type SlashMessage } from '#lib';
+import { type ArgumentGeneratorReturn } from '@notenoughupdates/discord-akairo';
import assert from 'assert/strict';
-import { type ArgumentGeneratorReturn } from 'discord-akairo';
import { type APIEmbed } from 'discord.js';
import { highlightSubcommands } from './highlight-!.js';
diff --git a/src/commands/utilities/highlight-unblock.ts b/src/commands/utilities/highlight-unblock.ts
index 0f2dd78..f9cc806 100644
--- a/src/commands/utilities/highlight-unblock.ts
+++ b/src/commands/utilities/highlight-unblock.ts
@@ -1,6 +1,6 @@
import { AllowedMentions, BotCommand, emojis, type ArgType, type CommandMessage, type SlashMessage } from '#lib';
+import { Argument, ArgumentGeneratorReturn } from '@notenoughupdates/discord-akairo';
import assert from 'assert';
-import { Argument, ArgumentGeneratorReturn } from 'discord-akairo';
import { BaseChannel, GuildMember, User } from 'discord.js';
import { HighlightUnblockResult } from '../../../lib/common/HighlightManager.js';
import { highlightSubcommands } from './highlight-!.js';
diff --git a/src/commands/utilities/price.ts b/src/commands/utilities/price.ts
index 6f08aaa..0d5d4b3 100644
--- a/src/commands/utilities/price.ts
+++ b/src/commands/utilities/price.ts
@@ -1,7 +1,9 @@
import { ArgType, BotCommand, colors, emojis, format, formatList, type CommandMessage } from '#lib';
import assert from 'assert/strict';
import { ApplicationCommandOptionType, AutocompleteInteraction, EmbedBuilder } from 'discord.js';
-import { default as Fuse } from 'fuse.js';
+
+// todo: remove this bullshit once typescript gets its shit together
+const Fuse = (await import('fuse.js')).default as unknown as typeof import('fuse.js').default;
assert(Fuse);
diff --git a/src/commands/utilities/steal.ts b/src/commands/utilities/steal.ts
index a208920..bd2976a 100644
--- a/src/commands/utilities/steal.ts
+++ b/src/commands/utilities/steal.ts
@@ -1,13 +1,11 @@
import { Arg, BotCommand, emojis, format, OptArgType, regex, type CommandMessage, type SlashMessage } from '#lib';
+import { type ArgumentGeneratorReturn, type ArgumentType, type ArgumentTypeCaster } from '@notenoughupdates/discord-akairo';
import assert from 'assert/strict';
-import { type ArgumentGeneratorReturn, type ArgumentType, type ArgumentTypeCaster } from 'discord-akairo';
import { ApplicationCommandOptionType, Attachment } from 'discord.js';
-import _ from 'lodash';
+import { snakeCase } from 'lodash-es';
import { Stream } from 'stream';
import { URL } from 'url';
-assert(_);
-
// so I don't have to retype things
const enum lang {
emojiStart = 'What emoji would you like to steal?',
@@ -53,7 +51,7 @@ export default class StealCommand extends BotCommand {
const name = yield {
prompt: { start: lang.nameStart, retry: lang.nameRetry, optional: true },
- default: hasImage && message.attachments.first()!.name ? _.snakeCase(message.attachments.first()!.name!) : 'unnamed_emoji'
+ default: hasImage && message.attachments.first()!.name ? snakeCase(message.attachments.first()!.name!) : 'unnamed_emoji'
};
return { emoji, name };
diff --git a/src/commands/utilities/whoHasRole.ts b/src/commands/utilities/whoHasRole.ts
index c01a0c3..31e413d 100644
--- a/src/commands/utilities/whoHasRole.ts
+++ b/src/commands/utilities/whoHasRole.ts
@@ -77,7 +77,7 @@ export default class WhoHasRoleCommand extends BotCommand {
return await message.util.reply(`${emojis.error} No members found matching the given roles.`);
}
- return await ButtonPaginator.send(message, embedPages, null, true);
+ return await ButtonPaginator.send(message, embedPages, '', true);
}
}
diff --git a/src/commands/utilities/wolframAlpha.ts b/src/commands/utilities/wolframAlpha.ts
index 503af87..48739cf 100644
--- a/src/commands/utilities/wolframAlpha.ts
+++ b/src/commands/utilities/wolframAlpha.ts
@@ -1,7 +1,7 @@
import { AllowedMentions, BotCommand, colors, emojis, type ArgType, type CommandMessage, type SlashMessage } from '#lib';
-import { initializeClass as WolframAlphaAPI } from '@notenoughupdates/wolfram-alpha-api';
+import { initializeClass as WolframAlphaAPI } from '@tanzanite/wolfram-alpha';
import assert from 'assert/strict';
-import { ApplicationCommandOptionType, EmbedBuilder, type MessageOptions } from 'discord.js';
+import { ApplicationCommandOptionType, EmbedBuilder, type MessageCreateOptions } from 'discord.js';
assert(WolframAlphaAPI);
@@ -62,7 +62,7 @@ export default class WolframAlphaCommand extends BotCommand {
name: '📥 Input',
value: await this.client.utils.inspectCleanRedactCodeblock(args.expression)
});
- const sendOptions: MessageOptions = { content: null, allowedMentions: AllowedMentions.none() };
+ const sendOptions: MessageCreateOptions = { content: '', allowedMentions: AllowedMentions.none() };
try {
const calculated = await (args.image
? waApi.getSimple({ i: args.expression, timeout: 1, background: '2C2F33', foreground: 'white' })
diff --git a/src/context-menu-commands/message/viewRaw.ts b/src/context-menu-commands/message/viewRaw.ts
index 0a8fcfc..08a421d 100644
--- a/src/context-menu-commands/message/viewRaw.ts
+++ b/src/context-menu-commands/message/viewRaw.ts
@@ -1,4 +1,4 @@
-import { ContextMenuCommand } from 'discord-akairo';
+import { ContextMenuCommand } from '@notenoughupdates/discord-akairo';
import { ApplicationCommandType, type ContextMenuCommandInteraction, type Message } from 'discord.js';
import { getRawData } from '../../commands/utilities/viewRaw.js';
diff --git a/src/context-menu-commands/user/modlog.ts b/src/context-menu-commands/user/modlog.ts
index c78396e..b68a7e9 100644
--- a/src/context-menu-commands/user/modlog.ts
+++ b/src/context-menu-commands/user/modlog.ts
@@ -1,6 +1,6 @@
import { ModlogCommand } from '#commands';
import { emojis, SlashMessage } from '#lib';
-import { CommandUtil, ContextMenuCommand } from 'discord-akairo';
+import { CommandUtil, ContextMenuCommand } from '@notenoughupdates/discord-akairo';
import { ApplicationCommandType, type ContextMenuCommandInteraction } from 'discord.js';
export default class ModlogContextMenuCommand extends ContextMenuCommand {
@@ -8,7 +8,8 @@ export default class ModlogContextMenuCommand extends ContextMenuCommand {
super('modlog', {
name: "Users's Modlogs",
type: ApplicationCommandType.User,
- category: 'user'
+ category: 'user',
+ dmPermission: false
});
}
@@ -28,6 +29,8 @@ export default class ModlogContextMenuCommand extends ContextMenuCommand {
const pseudoMessage = new SlashMessage(this.client, interaction as any);
pseudoMessage.util = new CommandUtil(this.client.commandHandler, pseudoMessage);
- void new ModlogCommand().exec(pseudoMessage, { search: interaction.targetId, hidden: false });
+ const command = this.client.commandHandler.modules.get('modlog') as ModlogCommand;
+
+ void command.exec(pseudoMessage, { search: interaction.targetId, hidden: false });
}
}
diff --git a/src/context-menu-commands/user/userInfo.ts b/src/context-menu-commands/user/userInfo.ts
index 6d7f3b6..283e4a0 100644
--- a/src/context-menu-commands/user/userInfo.ts
+++ b/src/context-menu-commands/user/userInfo.ts
@@ -1,27 +1,35 @@
import { UserInfoCommand } from '#commands';
-import { format } from '#lib';
-import { ContextMenuCommand } from 'discord-akairo';
-import { ApplicationCommandType, type ContextMenuCommandInteraction, type Guild } from 'discord.js';
+import { emojis } from '#lib';
+import { ContextMenuCommand } from '@notenoughupdates/discord-akairo';
+import assert from 'assert';
+import { ApplicationCommandType, GuildMember, UserContextMenuCommandInteraction } from 'discord.js';
export default class UserInfoContextMenuCommand extends ContextMenuCommand {
public constructor() {
super('userInfo', {
name: 'User Info',
type: ApplicationCommandType.User,
- category: 'user'
+ category: 'user',
+ dmPermission: false
});
}
- public override async exec(interaction: ContextMenuCommandInteraction) {
+ public override async exec(interaction: UserContextMenuCommandInteraction) {
+ if (!interaction.inCachedGuild())
+ return interaction.reply({
+ content: `${emojis.error} You can't use this command outside of a server.`,
+ ephemeral: true
+ });
+
await interaction.deferReply({ ephemeral: true });
- const user = await this.client.users.fetch(interaction.targetId).catch(() => null);
- if (!user) return interaction.reply(`⁉ I couldn't find that user`);
+ const user = interaction.targetUser;
+
+ const guild = interaction.guild ?? undefined;
- const guild = interaction.guild as Guild;
+ const member = interaction.targetMember ?? undefined;
- const member = await guild.members.fetch(interaction.targetId).catch(() => null);
- if (!member) return interaction.reply(`${format.input(user.tag)} doesn't appear to be a member of this server anymore.`);
+ assert(member instanceof GuildMember || member === undefined);
const userEmbed = await UserInfoCommand.makeUserInfoEmbed(user, member, guild);
diff --git a/src/listeners/bush/appealListener.ts b/src/listeners/bush/appealListener.ts
index 46859d1..99f1505 100644
--- a/src/listeners/bush/appealListener.ts
+++ b/src/listeners/bush/appealListener.ts
@@ -2,7 +2,7 @@ import { BotListener, colors, Emitter, mappings, ModLog, type BotClientEvents }
import assert from 'assert/strict';
import { EmbedBuilder, Events } from 'discord.js';
import UserInfoCommand from '../../commands/info/userInfo.js';
-import ModlogCommand from '../../commands/moderation/modlog.js';
+import { generateModlogInfo, modlogSeparator } from '../../commands/moderation/modlog.js';
export default class AppealListener extends BotListener {
public constructor() {
@@ -42,7 +42,9 @@ export default class AppealListener extends BotListener {
await ModLog.findAll({
where: {
user: user.id,
- guild: message.guildId
+ guild: message.guildId,
+ pseudo: false,
+ hidden: false
},
order: [['createdAt', 'DESC']]
})
@@ -60,15 +62,19 @@ export default class AppealListener extends BotListener {
member: {
if (!message.guild.members.cache.has(user.id)) break member;
+
const member = message.guild.members.cache.get(user.id)!;
+
UserInfoCommand.generateServerInfoField(embed, member);
- if (member.roles.cache.size > 1) UserInfoCommand.generateRolesField(embed, member);
+ if (member.roles.cache.size > 1) {
+ UserInfoCommand.generateRolesField(embed, member);
+ }
}
embed.addFields({
name: '» Latest Modlogs',
value: latestModlogs.length
- ? latestModlogs.map((ml) => ModlogCommand.generateModlogInfo(ml, false, false)).join(ModlogCommand.separator)
+ ? latestModlogs.map((ml) => generateModlogInfo(ml, false, false)).join(modlogSeparator)
: 'No Modlogs Found'
});
diff --git a/src/listeners/bush/experimentYoink.ts b/src/listeners/bush/experimentYoink.ts
new file mode 100644
index 0000000..5b7e526
--- /dev/null
+++ b/src/listeners/bush/experimentYoink.ts
@@ -0,0 +1,28 @@
+import { BotClientEvents, BotListener, Emitter, mappings } from '#lib';
+import { Events, Routes } from 'discord.js';
+
+export default class ExperimentYoink extends BotListener {
+ public constructor() {
+ super('experimentYoink', {
+ emitter: Emitter.Client,
+ event: Events.MessageCreate
+ });
+ }
+
+ public async exec(...[message]: BotClientEvents[Events.MessageCreate]): Promise<any> {
+ if (message.channelId !== '1019830755658055691') return;
+ if (message.embeds.length < 1) return;
+ if (!message.embeds[0].title?.includes('Guild Experiment')) return;
+
+ const guild = this.client.guilds.cache.get(mappings.guilds["Moulberry's Bush"]);
+
+ if (guild == null) return;
+
+ return await this.client.rest.post(Routes.channelMessages('795356494261911553'), {
+ body: {
+ content: message.content,
+ embeds: message.embeds.map((embed) => embed.toJSON())
+ }
+ });
+ }
+}
diff --git a/src/listeners/client/ready.ts b/src/listeners/client/ready.ts
index b74c132..e19c4eb 100644
--- a/src/listeners/client/ready.ts
+++ b/src/listeners/client/ready.ts
@@ -1,6 +1,9 @@
import { BotClientEvents, BotListener, Emitter, Guild } from '#lib';
+import { commas } from '#lib/common/tags.js';
+import { humanizeDuration } from '@notenoughupdates/humanize-duration';
import chalk from 'chalk';
import { Events } from 'discord.js';
+import { performance } from 'perf_hooks';
export default class ReadyListener extends BotListener {
public constructor() {
@@ -12,19 +15,28 @@ export default class ReadyListener extends BotListener {
// eslint-disable-next-line no-empty-pattern
public async exec(...[]: BotClientEvents[Events.ClientReady]) {
+ performance.mark('clientReady');
+
process.emit('ready' as any);
const tag = `<<${this.client.user?.tag}>>`,
- guildCount = `<<${this.client.guilds.cache.size.toLocaleString()}>>`,
- userCount = `<<${this.client.users.cache.size.toLocaleString()}>>`;
+ guildCount = commas`<<${this.client.guilds.cache.size}>>`,
+ userCount = commas`<<${this.client.users.cache.size}>>`;
void this.client.logger.success('ready', `Logged in to ${tag} serving ${guildCount} guilds and ${userCount} users.`);
- console.log(
- chalk.blue(
- `------------------------------------------------------------------------------${
- this.client.config.isDevelopment ? '---' : this.client.config.isBeta ? '----' : ''
- }`
- )
+
+ console.log(chalk.blue('-'.repeat(84 + (this.client.config.isDevelopment ? 3 : this.client.config.isBeta ? 4 : 0))));
+
+ const measure = performance.measure('start', 'processStart', 'clientReady');
+
+ void this.client.logger.info(
+ 'ready',
+ `Took <<${humanizeDuration(measure.duration, {
+ language: 'en',
+ largest: 3,
+ round: false,
+ maxDecimalPoints: 3
+ })}>> to start.`
);
const guilds = await Guild.findAll();
diff --git a/src/listeners/commands/commandBlocked.ts b/src/listeners/commands/commandBlocked.ts
index c81857c..7795241 100644
--- a/src/listeners/commands/commandBlocked.ts
+++ b/src/listeners/commands/commandBlocked.ts
@@ -9,7 +9,7 @@ import {
type BotCommandHandlerEvents,
type CommandMessage
} from '#lib';
-import { type Client, type InteractionReplyOptions, type ReplyMessageOptions } from 'discord.js';
+import { type Client, type InteractionReplyOptions, type MessageReplyOptions } from 'discord.js';
export default class CommandBlockedListener extends BotListener {
public constructor() {
@@ -124,7 +124,7 @@ export default class CommandBlockedListener extends BotListener {
}
// some inhibitors do not have message.util yet
- function respond(content: string | (ReplyMessageOptions & InteractionReplyOptions)) {
+ function respond(content: string | (MessageReplyOptions & InteractionReplyOptions)) {
return message.util ? message.util.reply(content) : message.reply(content);
}
}
diff --git a/src/listeners/contextCommands/contextCommandBlocked.ts b/src/listeners/contextCommands/contextCommandBlocked.ts
index 93b53c7..80c7a34 100644
--- a/src/listeners/contextCommands/contextCommandBlocked.ts
+++ b/src/listeners/contextCommands/contextCommandBlocked.ts
@@ -1,6 +1,6 @@
import { BotListener, ContextCommandHandlerEvent, Emitter, emojis, format } from '#lib';
-import { type ContextMenuCommandHandlerEvents } from 'discord-akairo';
-import { BuiltInReasons } from 'discord-akairo/dist/src/util/Constants.js';
+import { type ContextMenuCommandHandlerEvents } from '@notenoughupdates/discord-akairo';
+import { BuiltInReasons } from '@notenoughupdates/discord-akairo/dist/src/util/Constants.js';
export default class ContextCommandBlockedListener extends BotListener {
public constructor() {
diff --git a/src/listeners/contextCommands/contextCommandError.ts b/src/listeners/contextCommands/contextCommandError.ts
index 24e5cef..5043bae 100644
--- a/src/listeners/contextCommands/contextCommandError.ts
+++ b/src/listeners/contextCommands/contextCommandError.ts
@@ -9,7 +9,7 @@ import {
getErrorStack,
IFuckedUpError
} from '#lib';
-import { type ContextMenuCommand, type ContextMenuCommandHandlerEvents } from 'discord-akairo';
+import { type ContextMenuCommand, type ContextMenuCommandHandlerEvents } from '@notenoughupdates/discord-akairo';
import { ChannelType, Client, ContextMenuCommandInteraction, EmbedBuilder, GuildTextBasedChannel } from 'discord.js';
export default class ContextCommandErrorListener extends BotListener {
diff --git a/src/listeners/contextCommands/contextCommandNotFound.ts b/src/listeners/contextCommands/contextCommandNotFound.ts
index da364ed..e7538ee 100644
--- a/src/listeners/contextCommands/contextCommandNotFound.ts
+++ b/src/listeners/contextCommands/contextCommandNotFound.ts
@@ -1,5 +1,5 @@
import { BotListener, ContextCommandHandlerEvent, Emitter } from '#lib';
-import { type ContextMenuCommandHandlerEvents } from 'discord-akairo';
+import { type ContextMenuCommandHandlerEvents } from '@notenoughupdates/discord-akairo';
export default class ContextCommandNotFoundListener extends BotListener {
public constructor() {
diff --git a/src/listeners/contextCommands/contextCommandStarted.ts b/src/listeners/contextCommands/contextCommandStarted.ts
index bf7cc58..a820d3e 100644
--- a/src/listeners/contextCommands/contextCommandStarted.ts
+++ b/src/listeners/contextCommands/contextCommandStarted.ts
@@ -1,5 +1,5 @@
import { BotListener, ContextCommandHandlerEvent, Emitter } from '#lib';
-import { ContextMenuCommandHandlerEvents } from 'discord-akairo';
+import { ContextMenuCommandHandlerEvents } from '@notenoughupdates/discord-akairo';
import { ApplicationCommandType, ChannelType } from 'discord.js';
export default class ContextCommandStartedListener extends BotListener {
diff --git a/src/listeners/guild/syncUnbanPunishmentModel.ts b/src/listeners/guild/syncUnbanPunishmentModel.ts
index eac3aa2..c6de768 100644
--- a/src/listeners/guild/syncUnbanPunishmentModel.ts
+++ b/src/listeners/guild/syncUnbanPunishmentModel.ts
@@ -13,7 +13,7 @@ export default class SyncUnbanListener extends BotListener {
where: {
user: ban.user.id,
guild: ban.guild.id,
- type: ActivePunishmentType.BAN
+ type: ActivePunishmentType.Ban
}
});
for (const dbBan of bans) {
diff --git a/src/listeners/interaction/$interactionCreate.ts b/src/listeners/interaction/$interactionCreate.ts
new file mode 100644
index 0000000..86aa5e2
--- /dev/null
+++ b/src/listeners/interaction/$interactionCreate.ts
@@ -0,0 +1,31 @@
+import { BotListener, Emitter, TanzaniteEvent, type BotClientEvents } from '#lib';
+import { Events, InteractionType } from 'discord.js';
+
+export default class InteractionCreateListener extends BotListener {
+ public constructor() {
+ super('interactionCreate', {
+ emitter: Emitter.Client,
+ event: Events.InteractionCreate
+ });
+ }
+
+ public async exec(...[interaction]: BotClientEvents[Events.InteractionCreate]) {
+ if (!interaction) return;
+
+ void this.client.console.verbose(
+ 'interactionVerbose',
+ `An interaction of type <<${InteractionType[interaction.type]}>> was received from <<${interaction.user.tag}>>.`
+ );
+
+ if (interaction.isCommand() || interaction.isAutocomplete()) {
+ // handled by the command handler
+ return;
+ } else if (interaction.isButton()) {
+ this.client.emit(TanzaniteEvent.Button, interaction);
+ } else if (interaction.isModalSubmit()) {
+ this.client.emit(TanzaniteEvent.ModalSubmit, interaction);
+ } else if (interaction.isSelectMenu()) {
+ this.client.emit(TanzaniteEvent.SelectMenu, interaction);
+ }
+ }
+}
diff --git a/src/listeners/interaction/button.ts b/src/listeners/interaction/button.ts
index e69de29..d0730d5 100644
--- a/src/listeners/interaction/button.ts
+++ b/src/listeners/interaction/button.ts
@@ -0,0 +1,129 @@
+import {
+ BotClientEvents,
+ BotListener,
+ Emitter,
+ emojis,
+ handleAppealAttempt,
+ handleAppealDecision,
+ handleAutomodInteraction,
+ TanzaniteEvent
+} from '#lib';
+import {
+ ActionRowData,
+ ButtonInteraction,
+ ComponentType,
+ ModalActionRowComponentData,
+ TextInputComponentData,
+ TextInputStyle
+} from 'discord.js';
+
+export default class ButtonListener extends BotListener {
+ public constructor() {
+ super(TanzaniteEvent.Button, {
+ emitter: Emitter.Client,
+ event: TanzaniteEvent.Button
+ });
+ }
+
+ public async exec(...[interaction]: BotClientEvents[TanzaniteEvent.Button]) {
+ const { customId } = interaction;
+
+ if (customId.startsWith('automod;')) {
+ return void handleAutomodInteraction(interaction);
+ } else if (customId.startsWith('button-role;')) {
+ return void this.handleButtonRoles(interaction);
+ } else if (customId === 'test;modal') {
+ return this.handleTestModal(interaction);
+ } else if (customId.startsWith('test;lots;') || customId.startsWith('test;button;')) {
+ return await interaction.reply({
+ content: 'Buttons go brrr',
+ ephemeral: true
+ });
+ } else if (customId.startsWith('appeal_attempt;')) {
+ return handleAppealAttempt(interaction);
+ } else if (customId.startsWith('appeal_accept;') || customId.startsWith('appeal_deny;')) {
+ return handleAppealDecision(interaction);
+ }
+ }
+
+ private async handleButtonRoles(interaction: ButtonInteraction) {
+ if (!interaction.inCachedGuild()) return;
+
+ const [, roleId] = interaction.customId.split(';');
+ const role = interaction.guild.roles.cache.get(roleId);
+ if (!role) {
+ return interaction.reply({
+ content: `${emojis.error} That role does not exist.`,
+ ephemeral: true
+ });
+ }
+ const has = interaction.member.roles.cache.has(roleId);
+ await interaction.deferReply({ ephemeral: true });
+ if (has) {
+ const success = await interaction.member.roles.remove(roleId).catch(() => false);
+ if (success) {
+ return interaction.editReply({
+ content: `${emojis.success} Removed the ${role} role from you.`,
+ allowedMentions: {}
+ });
+ } else {
+ return interaction.editReply({
+ content: `${emojis.error} Failed to remove ${role} from you.`,
+ allowedMentions: {}
+ });
+ }
+ } else {
+ const success = await interaction.member.roles.add(roleId).catch(() => false);
+ if (success) {
+ return interaction.editReply({
+ content: `${emojis.success} Added the ${role} role to you.`,
+ allowedMentions: {}
+ });
+ } else {
+ return interaction.editReply({
+ content: `${emojis.error} Failed to add ${role} to you.`,
+ allowedMentions: {}
+ });
+ }
+ }
+ }
+
+ private async handleTestModal(interaction: ButtonInteraction) {
+ const shortText = (
+ options: Pick<TextInputComponentData, 'customId' | 'label' | 'placeholder'> & Partial<TextInputComponentData>
+ ): ActionRowData<ModalActionRowComponentData> => ({
+ type: ComponentType.ActionRow as const,
+ components: [
+ {
+ type: ComponentType.TextInput as const,
+ style: TextInputStyle.Short as const,
+ ...options
+ }
+ ]
+ });
+
+ return interaction.showModal({
+ customId: 'test;login',
+ title: 'Login (real)',
+ components: [
+ shortText({
+ customId: 'test;login;email',
+ label: 'Email',
+ placeholder: 'Email'
+ }),
+ shortText({
+ customId: 'test;login;password',
+ label: 'Password',
+ placeholder: 'Password'
+ }),
+ shortText({
+ customId: 'test;login;2fa',
+ label: 'Enter Discord Auth Code',
+ minLength: 6,
+ maxLength: 6,
+ placeholder: '6-digit authentication code'
+ })
+ ]
+ });
+ }
+}
diff --git a/src/listeners/interaction/interactionCreate.ts b/src/listeners/interaction/interactionCreate.ts
deleted file mode 100644
index ced359c..0000000
--- a/src/listeners/interaction/interactionCreate.ts
+++ /dev/null
@@ -1,78 +0,0 @@
-import {
- BotListener,
- Emitter,
- emojis,
- format,
- formatList,
- handleAutomodInteraction,
- surroundEach,
- type BotClientEvents
-} from '#lib';
-import { Events, InteractionType } from 'discord.js';
-
-export default class InteractionCreateListener extends BotListener {
- public constructor() {
- super('interactionCreate', {
- emitter: Emitter.Client,
- event: Events.InteractionCreate
- });
- }
-
- public async exec(...[interaction]: BotClientEvents[Events.InteractionCreate]) {
- if (!interaction) return;
- if ('customId' in interaction && (interaction as any)['customId'].startsWith('test')) return;
- void this.client.console.verbose(
- 'interactionVerbose',
- `An interaction of type <<${InteractionType[interaction.type]}>> was received from <<${interaction.user.tag}>>.`
- );
- if (interaction.type === InteractionType.ApplicationCommand) {
- return;
- } else if (interaction.isButton()) {
- const id = interaction.customId;
- if (['paginate_', 'command_', 'confirmationPrompt_', 'appeal'].some((s) => id.startsWith(s))) return;
- else if (id.startsWith('automod;')) void handleAutomodInteraction(interaction);
- else if (id.startsWith('button-role;') && interaction.inCachedGuild()) {
- const [, roleId] = id.split(';');
- const role = interaction.guild.roles.cache.get(roleId);
- if (!role) return interaction.reply({ content: `${emojis.error} That role does not exist.`, ephemeral: true });
- const has = interaction.member.roles.cache.has(roleId);
- await interaction.deferReply({ ephemeral: true });
- if (has) {
- const success = await interaction.member.roles.remove(roleId).catch(() => false);
- if (success)
- return interaction.editReply({
- content: `${emojis.success} Removed the ${role} role from you.`,
- allowedMentions: {}
- });
- else
- return interaction.editReply({
- content: `${emojis.error} Failed to remove ${role} from you.`,
- allowedMentions: {}
- });
- } else {
- const success = await interaction.member.roles.add(roleId).catch(() => false);
- if (success)
- return interaction.editReply({
- content: `${emojis.success} Added the ${role} role to you.`,
- allowedMentions: {}
- });
- else
- return interaction.editReply({
- content: `${emojis.error} Failed to add ${role} to you.`,
- allowedMentions: {}
- });
- }
- } else return await interaction.reply({ content: 'Buttons go brrr', ephemeral: true });
- } else if (interaction.isSelectMenu()) {
- if (interaction.customId.startsWith('command_')) return;
- return await interaction.reply({
- content: `You selected ${
- Array.isArray(interaction.values)
- ? formatList(surroundEach(interaction.values, '`'), 'and')
- : format.input(interaction.values)
- }.`,
- ephemeral: true
- });
- }
- }
-}
diff --git a/src/listeners/interaction/modalSubmit.ts b/src/listeners/interaction/modalSubmit.ts
new file mode 100644
index 0000000..8cf93f4
--- /dev/null
+++ b/src/listeners/interaction/modalSubmit.ts
@@ -0,0 +1,20 @@
+import { BotClientEvents, BotListener, Emitter, emojis, handleAppealSubmit, TanzaniteEvent } from '#lib';
+
+export default class ModalSubmitListener extends BotListener {
+ public constructor() {
+ super(TanzaniteEvent.ModalSubmit, {
+ emitter: Emitter.Client,
+ event: TanzaniteEvent.ModalSubmit
+ });
+ }
+
+ public async exec(...[interaction]: BotClientEvents[TanzaniteEvent.ModalSubmit]) {
+ const { customId } = interaction;
+
+ if (customId === 'test;login') {
+ return interaction.reply({ content: `${emojis.loading} Selling your account information to Facebook...`, ephemeral: true });
+ } else if (customId.startsWith('appeal_submit;')) {
+ return handleAppealSubmit(interaction);
+ }
+ }
+}
diff --git a/src/listeners/interaction/selectMenu.ts b/src/listeners/interaction/selectMenu.ts
new file mode 100644
index 0000000..112f303
--- /dev/null
+++ b/src/listeners/interaction/selectMenu.ts
@@ -0,0 +1,23 @@
+import { BotClientEvents, BotListener, Emitter, format, formatList, surroundEach, TanzaniteEvent } from '#lib';
+
+export default class SelectMenuListener extends BotListener {
+ public constructor() {
+ super(TanzaniteEvent.SelectMenu, {
+ emitter: Emitter.Client,
+ event: TanzaniteEvent.SelectMenu
+ });
+ }
+
+ public async exec(...[interaction]: BotClientEvents[TanzaniteEvent.SelectMenu]) {
+ if (interaction.customId.startsWith('command_')) return;
+
+ return await interaction.reply({
+ content: `You selected ${
+ Array.isArray(interaction.values)
+ ? formatList(surroundEach(interaction.values, '`'), 'and')
+ : format.input(interaction.values)
+ }.`,
+ ephemeral: true
+ });
+ }
+}
diff --git a/src/listeners/member-custom/levelUpdate.ts b/src/listeners/member-custom/levelUpdate.ts
index 53734fd..7d3cee7 100644
--- a/src/listeners/member-custom/levelUpdate.ts
+++ b/src/listeners/member-custom/levelUpdate.ts
@@ -29,11 +29,12 @@ export default class LevelUpdateListener extends BotListener {
.send(`${format.input(member.user.tag)} leveled up to level ${format.input(`${newLevel}`)}.`)
.catch(() => null);
- if (!success)
+ if (!success) {
await message.guild.error(
'LevelUpdate',
`Could not send level up message for ${member.user.tag} in <#${message.channel.id}>.`
);
+ }
}
private async assignLevelRoles(member: Args[0], newLevel: Args[2], message: Args[4]) {
diff --git a/src/listeners/message/autoPublisher.ts b/src/listeners/message/autoPublisher.ts
index 36c448a..46577e4 100644
--- a/src/listeners/message/autoPublisher.ts
+++ b/src/listeners/message/autoPublisher.ts
@@ -13,7 +13,10 @@ export default class autoPublisherListener extends BotListener {
if (!message.guild || !(await message.guild.hasFeature('autoPublish'))) return;
const autoPublishChannels = await message.guild.getSetting('autoPublishChannels');
if (autoPublishChannels) {
- if (message.channel.type === ChannelType.GuildNews && autoPublishChannels.some((x) => message.channel.id.includes(x))) {
+ if (
+ message.channel.type === ChannelType.GuildAnnouncement &&
+ autoPublishChannels.some((x) => message.channel.id.includes(x))
+ ) {
await message
.crosspost()
.then(
diff --git a/src/listeners/message/level.ts b/src/listeners/message/level.ts
index a445d1e..60742ab 100644
--- a/src/listeners/message/level.ts
+++ b/src/listeners/message/level.ts
@@ -3,6 +3,7 @@ import { MessageType } from 'discord.js';
export default class LevelListener extends BotListener {
#levelCooldowns: Set<string> = new Set();
+
public constructor() {
super('level', {
emitter: Emitter.CommandHandler,
@@ -14,34 +15,52 @@ export default class LevelListener extends BotListener {
public async exec(...[message]: BotCommandHandlerEvents[CommandHandlerEvent.MessageInvalid]) {
if (message.author.bot || !message.author || !message.inGuild()) return;
if (!(await message.guild.hasFeature('leveling'))) return;
- if (this.#levelCooldowns.has(`${message.guildId}-${message.author.id}`)) return;
+
+ const lock = `${message.guildId}-${message.author.id}`;
+ if (this.#levelCooldowns.has(lock)) return;
if ((await message.guild.getSetting('noXpChannels')).includes(message.channel.id)) return;
- if (message.type !== MessageType.Default && message.type !== MessageType.Reply) return; //checks for join messages, slash commands, booster messages etc
- const [user] = await Level.findOrBuild({
+
+ // checks for join messages, slash commands, booster messages etc
+ if (![MessageType.Default, MessageType.Reply, MessageType.ThreadStarterMessage].includes(message.type)) {
+ return;
+ }
+
+ const [levelEntry] = await Level.findOrBuild({
where: {
user: message.author.id,
guild: message.guildId
- },
- defaults: {
- user: message.author.id,
- guild: message.guildId,
- xp: 0
}
});
- const previousLevel = Level.convertXpToLevel(user.xp);
+
+ const previousLevel = Level.convertXpToLevel(levelEntry.xp);
const xpToGive = Level.genRandomizedXp();
- user.xp = user.xp + xpToGive;
- const success = await user.save().catch((e) => {
- void this.client.utils.handleError('level', e);
+
+ let xp = levelEntry.xp + xpToGive;
+
+ if (xp > Level.MAX_XP) {
+ xp = Level.MAX_XP;
+ }
+
+ const success = await levelEntry.update({ xp, user: message.author.id, guild: message.guild.id }).catch((e) => {
+ void this.client.utils.handleError('LevelListener', e);
+
return false;
});
- const newLevel = Level.convertXpToLevel(user.xp);
- if (previousLevel !== newLevel)
- this.client.emit(TanzaniteEvent.LevelUpdate, message.member!, previousLevel, newLevel, user.xp, message);
- if (success)
- void this.client.logger.verbose(`level`, `Gave <<${xpToGive}>> XP to <<${message.author.tag}>> in <<${message.guild}>>.`);
- this.#levelCooldowns.add(`${message.guildId}-${message.author.id}`);
- setTimeout(() => this.#levelCooldowns.delete(`${message.guildId}-${message.author.id}`), 60_000);
+
+ const newLevel = Level.convertXpToLevel(levelEntry.xp);
+
+ if (success) {
+ if (previousLevel !== newLevel) {
+ // level up messages and level roles
+ this.client.emit(TanzaniteEvent.LevelUpdate, message.member!, previousLevel, newLevel, levelEntry.xp, message);
+ }
+
+ void this.client.logger.verbose(`level`, `Gave <<${xpToGive}>> xp to <<${message.author.tag}>> in <<${message.guild}>>.`);
+ }
+
+ this.#levelCooldowns.add(lock);
+
+ setTimeout(() => this.#levelCooldowns.delete(lock), 60_000);
}
}
diff --git a/src/listeners/message/quoteCreate.ts b/src/listeners/message/quoteCreate.ts
index 1c3130c..fca6c9f 100644
--- a/src/listeners/message/quoteCreate.ts
+++ b/src/listeners/message/quoteCreate.ts
@@ -10,7 +10,7 @@ export default class QuoteCreateListener extends BotListener {
}
public async exec(...[message]: BotClientEvents[Events.MessageCreate]) {
- if (message.author.id !== mappings.users['IRONM00N'] || !this.client.config.isProduction) return;
+ if (message.author.id !== mappings.users['IRONM00N'] /* || !this.client.config.isProduction */) return;
if (!message.inGuild()) return;
const messages = await this.client.utils.resolveMessagesFromLinks(message.content);
diff --git a/src/listeners/track-manual-punishments/modlogSyncBan.ts b/src/listeners/track-manual-punishments/modlogSyncBan.ts
index 83f6dd4..5a4d768 100644
--- a/src/listeners/track-manual-punishments/modlogSyncBan.ts
+++ b/src/listeners/track-manual-punishments/modlogSyncBan.ts
@@ -37,7 +37,7 @@ export default class ModlogSyncBanListener extends BotListener {
const { log } = await Moderation.createModLogEntry({
client: this.client,
- type: ModLogType.PERM_BAN,
+ type: ModLogType.PermBan,
user: ban.user,
moderator: first.executor,
reason: `[Manual] ${first.reason ? first.reason : 'No reason given'}`,
diff --git a/src/listeners/track-manual-punishments/modlogSyncKick.ts b/src/listeners/track-manual-punishments/modlogSyncKick.ts
index e8b2433..a05e666 100644
--- a/src/listeners/track-manual-punishments/modlogSyncKick.ts
+++ b/src/listeners/track-manual-punishments/modlogSyncKick.ts
@@ -37,7 +37,7 @@ export default class ModlogSyncKickListener extends BotListener {
const { log } = await Moderation.createModLogEntry({
client: this.client,
- type: ModLogType.KICK,
+ type: ModLogType.Kick,
user: member.user,
moderator: first.executor,
reason: `[Manual] ${first.reason ? first.reason : 'No reason given'}`,
diff --git a/src/listeners/track-manual-punishments/modlogSyncTimeout.ts b/src/listeners/track-manual-punishments/modlogSyncTimeout.ts
index 2a4e0bb..f6abbab 100644
--- a/src/listeners/track-manual-punishments/modlogSyncTimeout.ts
+++ b/src/listeners/track-manual-punishments/modlogSyncTimeout.ts
@@ -41,7 +41,7 @@ export default class ModlogSyncTimeoutListener extends BotListener {
const { log } = await Moderation.createModLogEntry({
client: this.client,
- type: newTime ? ModLogType.TIMEOUT : ModLogType.REMOVE_TIMEOUT,
+ type: newTime ? ModLogType.Timeout : ModLogType.RemoveTimeout,
user: newMember.user,
moderator: first.executor,
reason: `[Manual] ${first.reason ? first.reason : 'No reason given'}`,
diff --git a/src/listeners/track-manual-punishments/modlogSyncUnban.ts b/src/listeners/track-manual-punishments/modlogSyncUnban.ts
index 4738066..35ee3d2 100644
--- a/src/listeners/track-manual-punishments/modlogSyncUnban.ts
+++ b/src/listeners/track-manual-punishments/modlogSyncUnban.ts
@@ -36,7 +36,7 @@ export default class ModlogSyncUnbanListener extends BotListener {
const { log } = await Moderation.createModLogEntry({
client: this.client,
- type: ModLogType.UNBAN,
+ type: ModLogType.Unban,
user: ban.user,
moderator: first.executor,
reason: `[Manual] ${first.reason ? first.reason : 'No reason given'}`,
diff --git a/src/listeners/ws/INTERACTION_CREATE.ts b/src/listeners/ws/INTERACTION_CREATE.ts
index d0327df..49f8bdf 100644
--- a/src/listeners/ws/INTERACTION_CREATE.ts
+++ b/src/listeners/ws/INTERACTION_CREATE.ts
@@ -1,25 +1,5 @@
-import { BotListener, capitalize, colors, Emitter, emojis, Moderation, PunishmentTypePresent } from '#lib';
-import assert from 'assert/strict';
-import {
- ActionRowBuilder,
- ButtonBuilder,
- ButtonStyle,
- ComponentType,
- EmbedBuilder,
- GatewayDispatchEvents,
- InteractionResponseType,
- InteractionType,
- Routes,
- Snowflake,
- TextInputStyle,
- User,
- type APIEmbed,
- type APIInteraction,
- type APIInteractionResponseChannelMessageWithSource,
- type APIInteractionResponseDeferredMessageUpdate,
- type APIInteractionResponseUpdateMessage,
- type APIModalInteractionResponse
-} from 'discord.js';
+import { BotListener, Emitter } from '#lib';
+import { GatewayDispatchEvents, type APIInteraction } from 'discord.js';
export default class WsInteractionCreateListener extends BotListener {
public constructor() {
@@ -29,215 +9,5 @@ export default class WsInteractionCreateListener extends BotListener {
});
}
- public async exec(interaction: APIInteraction) {
- // console.dir(interaction);
-
- 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 = this.client.guilds.resolve(guildId);
- if (!guild)
- return respond({
- type: InteractionResponseType.ChannelMessageWithSource,
- data: {
- content: `${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: `${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 this.client.users
- .send(userId, `Your ${punishment} appeal has been denied in ${this.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 = this.client.guilds.resolve(guildId);
- if (!guild)
- return respond({
- type: InteractionResponseType.ChannelMessageWithSource,
- data: {
- content: `${emojis.error} I am no longer in that server.`
- }
- });
-
- const channel = await guild.getLogChannel('appeals');
- if (!channel)
- return respond({
- type: InteractionResponseType.ChannelMessageWithSource,
- data: {
- content: `${emojis.error} ${guild.name} has misconfigured their appeals channel.`
- }
- });
-
- assert(interaction.user);
- const user = new User(this.client, interaction.user);
- assert(user);
-
- // const caseId = await ModLog.findOne({ where: { user: userId, guild: guildId, id: modlogCase } });
-
- const embed = new EmbedBuilder()
- .setTitle(`${capitalize(punishment)} Appeal`)
- .setColor(colors.newBlurple)
- .setTimestamp()
- .setFooter({ text: `CaseID: ${modlogCase}` })
- .setAuthor({ name: user.tag, iconURL: user.displayAvatarURL() })
- .addFields(
- {
- name: `Why were you ${Moderation.punishmentToPastTense(punishment)}?`,
- value: interaction.data.components![0].components[0]!.value.substring(0, 1024)
- },
- {
- name: 'Do you believe it was fair?',
- value: interaction.data.components![1].components[0]!.value.substring(0, 1024)
- },
- {
- name: `Why should your ${punishment} be removed?`,
- value: interaction.data.components![2].components[0]!.value.substring(0, 1024)
- }
- )
- .toJSON() as APIEmbed;
-
- const components = [
- new ActionRowBuilder<ButtonBuilder>({
- components: [
- new ButtonBuilder({
- customId: `appeal_accept;${punishment};${guildId};${userId};${modlogCase}`,
- label: 'Accept',
- style: ButtonStyle.Success
- }).toJSON(),
- new ButtonBuilder({
- customId: `appeal_deny;${punishment};${guildId};${userId};${modlogCase}`,
- label: 'Deny',
- style: ButtonStyle.Danger
- }).toJSON()
- ]
- })
- ];
-
- await channel.send({ embeds: [embed], components });
- } else {
- return deferredMessageUpdate();
- }
- }
- }
+ public async exec(interaction: APIInteraction) {}
}
diff --git a/src/tasks/feature/removeExpiredPunishements.ts b/src/tasks/feature/removeExpiredPunishements.ts
index eac325a..5d5d5ab 100644
--- a/src/tasks/feature/removeExpiredPunishements.ts
+++ b/src/tasks/feature/removeExpiredPunishements.ts
@@ -35,7 +35,7 @@ export default class RemoveExpiredPunishmentsTask extends BotTask {
assert(guild);
switch (entry.type) {
- case ActivePunishmentType.BAN: {
+ case ActivePunishmentType.Ban: {
assert(user);
const result = await guild.customUnban({ user: user, reason: 'Punishment expired' });
if (['success', 'user not banned', 'cannot resolve user'].includes(result)) await entry.destroy();
@@ -43,7 +43,7 @@ export default class RemoveExpiredPunishmentsTask extends BotTask {
void this.client.logger.verbose(`removeExpiredPunishments`, `Unbanned ${entry.user}.`);
break;
}
- case ActivePunishmentType.BLOCK: {
+ case ActivePunishmentType.Block: {
if (!member) {
await entry.destroy(); // channel overrides are removed when the member leaves the guild
return;
@@ -54,7 +54,7 @@ export default class RemoveExpiredPunishmentsTask extends BotTask {
void this.client.logger.verbose(`removeExpiredPunishments`, `Unblocked ${entry.user}.`);
break;
}
- case ActivePunishmentType.MUTE: {
+ case ActivePunishmentType.Mute: {
if (!member) return;
const result = await member.customUnmute({ reason: 'Punishment expired' });
if (['success', 'failed to dm'].includes(result)) await entry.destroy();
@@ -62,7 +62,7 @@ export default class RemoveExpiredPunishmentsTask extends BotTask {
void this.client.logger.verbose(`removeExpiredPunishments`, `Unmuted ${entry.user}.`);
break;
}
- case ActivePunishmentType.ROLE: {
+ case ActivePunishmentType.Role: {
if (!member) return;
const role = guild?.roles?.cache?.get(entry.extraInfo);
if (!role) throw new Error(`Cannot unmute ${member.user.tag} because I cannot find the mute role.`);
diff --git a/yarn.lock b/yarn.lock
index 13f66b0..8510f05 100644
--- a/yarn.lock
+++ b/yarn.lock
@@ -5,16 +5,16 @@ __metadata:
version: 6
cacheKey: 8
-"@babel/runtime@npm:^7.18.9":
- version: 7.18.9
- resolution: "@babel/runtime@npm:7.18.9"
+"@babel/runtime@npm:^7.19.0":
+ version: 7.19.0
+ resolution: "@babel/runtime@npm:7.19.0"
dependencies:
regenerator-runtime: ^0.13.4
- checksum: 36dd736baba7164e82b3cc9d43e081f0cb2d05ff867ad39cac515d99546cee75b7f782018b02a3dcf5f2ef3d27f319faa68965fdfec49d4912c60c6002353a2e
+ checksum: fa69c351bb05e1db3ceb9a02fdcf620c234180af68cdda02152d3561015f6d55277265d3109815992f96d910f3db709458cae4f8df1c3def66f32e0867d82294
languageName: node
linkType: hard
-"@discordjs/builders@npm:^1.1.0":
+"@discordjs/builders@npm:^1.2.0":
version: 1.2.0
resolution: "@discordjs/builders@npm:1.2.0"
dependencies:
@@ -27,38 +27,45 @@ __metadata:
languageName: node
linkType: hard
-"@discordjs/collection@npm:^1.0.1":
+"@discordjs/collection@npm:^1.1.0":
version: 1.1.0
resolution: "@discordjs/collection@npm:1.1.0"
checksum: 9a78763a181130d91b51d0d93553fd75d09d0aabd6556890a35404bbefe9c5112cb74c3b1e486a213607f6577f9d2d8ee94ee3177652116bac80516e7d3083d6
languageName: node
linkType: hard
-"@discordjs/rest@npm:^1.0.1":
- version: 1.1.0
- resolution: "@discordjs/rest@npm:1.1.0"
+"@discordjs/rest@npm:^1.2.0":
+ version: 1.2.0
+ resolution: "@discordjs/rest@npm:1.2.0"
dependencies:
- "@discordjs/collection": ^1.0.1
+ "@discordjs/collection": ^1.1.0
"@sapphire/async-queue": ^1.5.0
"@sapphire/snowflake": ^3.2.2
- discord-api-types: ^0.37.3
- file-type: ^17.1.6
+ discord-api-types: ^0.37.10
+ file-type: ^18.0.0
tslib: ^2.4.0
- undici: ^5.9.1
- checksum: b216d5b217bf70a713480738851a0e607cbed267a0ad60942268f9761c605aac6552fd9cdda56bcabe332f6e5ccb5b7ce9911645e24d3d9342ed6f18dccc6b94
+ undici: ^5.10.0
+ checksum: fa414f2a92e94ad587c0a793e5a378cc0597ed062fe1509314b7c29f925b7a9cc013efad8f572f589d520a9dca4f19a4cc2403f14b89d38e6c61aa2292d96cfe
+ languageName: node
+ linkType: hard
+
+"@esbuild/android-arm@npm:0.15.9":
+ version: 0.15.9
+ resolution: "@esbuild/android-arm@npm:0.15.9"
+ conditions: os=android & cpu=arm
languageName: node
linkType: hard
-"@esbuild/linux-loong64@npm:0.14.54":
- version: 0.14.54
- resolution: "@esbuild/linux-loong64@npm:0.14.54"
+"@esbuild/linux-loong64@npm:0.15.9":
+ version: 0.15.9
+ resolution: "@esbuild/linux-loong64@npm:0.15.9"
conditions: os=linux & cpu=loong64
languageName: node
linkType: hard
-"@eslint/eslintrc@npm:^1.3.1":
- version: 1.3.1
- resolution: "@eslint/eslintrc@npm:1.3.1"
+"@eslint/eslintrc@npm:^1.3.2":
+ version: 1.3.2
+ resolution: "@eslint/eslintrc@npm:1.3.2"
dependencies:
ajv: ^6.12.4
debug: ^4.3.2
@@ -69,7 +76,7 @@ __metadata:
js-yaml: ^4.1.0
minimatch: ^3.1.2
strip-json-comments: ^3.1.1
- checksum: 9844dcc58a44399649926d5a17a2d53d529b80d3e8c3e9d0964ae198bac77ee6bb1cf44940f30cd9c2e300f7568ec82500be42ace6cacefb08aebf9905fe208e
+ checksum: 2074dca47d7e1c5c6323ff353f690f4b25d3ab53fe7d27337e2592d37a894cf60ca0e85ca66b50ff2db0bc7e630cc1e9c7347d65bb185b61416565584c38999c
languageName: node
linkType: hard
@@ -80,14 +87,14 @@ __metadata:
languageName: node
linkType: hard
-"@humanwhocodes/config-array@npm:^0.10.4":
- version: 0.10.4
- resolution: "@humanwhocodes/config-array@npm:0.10.4"
+"@humanwhocodes/config-array@npm:^0.10.5":
+ version: 0.10.5
+ resolution: "@humanwhocodes/config-array@npm:0.10.5"
dependencies:
"@humanwhocodes/object-schema": ^1.2.1
debug: ^4.1.1
minimatch: ^3.0.4
- checksum: d480e5d57e6d787565b6cff78e27c3d1b380692d4ffb0ada7d7f5957a56c9032f034da05a3e443065dbd0671ebf4d859036ced34e96b325bbc1badbae3c05300
+ checksum: af4fa2633c57414be22ddba0a072cc611ef9a07104542fa24bde918a0153b89b6e08ca6a20ccc9079de6079e219e2406e38414d1b662db8bb59a3ba9d6eee6e3
languageName: node
linkType: hard
@@ -119,82 +126,82 @@ __metadata:
languageName: node
linkType: hard
-"@napi-rs/canvas-android-arm64@npm:0.1.29":
- version: 0.1.29
- resolution: "@napi-rs/canvas-android-arm64@npm:0.1.29"
+"@napi-rs/canvas-android-arm64@npm:0.1.30":
+ version: 0.1.30
+ resolution: "@napi-rs/canvas-android-arm64@npm:0.1.30"
conditions: os=android & cpu=arm64
languageName: node
linkType: hard
-"@napi-rs/canvas-darwin-arm64@npm:0.1.29":
- version: 0.1.29
- resolution: "@napi-rs/canvas-darwin-arm64@npm:0.1.29"
+"@napi-rs/canvas-darwin-arm64@npm:0.1.30":
+ version: 0.1.30
+ resolution: "@napi-rs/canvas-darwin-arm64@npm:0.1.30"
conditions: os=darwin & cpu=arm64
languageName: node
linkType: hard
-"@napi-rs/canvas-darwin-x64@npm:0.1.29":
- version: 0.1.29
- resolution: "@napi-rs/canvas-darwin-x64@npm:0.1.29"
+"@napi-rs/canvas-darwin-x64@npm:0.1.30":
+ version: 0.1.30
+ resolution: "@napi-rs/canvas-darwin-x64@npm:0.1.30"
conditions: os=darwin & cpu=x64
languageName: node
linkType: hard
-"@napi-rs/canvas-linux-arm-gnueabihf@npm:0.1.29":
- version: 0.1.29
- resolution: "@napi-rs/canvas-linux-arm-gnueabihf@npm:0.1.29"
+"@napi-rs/canvas-linux-arm-gnueabihf@npm:0.1.30":
+ version: 0.1.30
+ resolution: "@napi-rs/canvas-linux-arm-gnueabihf@npm:0.1.30"
conditions: os=linux & cpu=arm
languageName: node
linkType: hard
-"@napi-rs/canvas-linux-arm64-gnu@npm:0.1.29":
- version: 0.1.29
- resolution: "@napi-rs/canvas-linux-arm64-gnu@npm:0.1.29"
+"@napi-rs/canvas-linux-arm64-gnu@npm:0.1.30":
+ version: 0.1.30
+ resolution: "@napi-rs/canvas-linux-arm64-gnu@npm:0.1.30"
conditions: os=linux & cpu=arm64 & libc=glibc
languageName: node
linkType: hard
-"@napi-rs/canvas-linux-arm64-musl@npm:0.1.29":
- version: 0.1.29
- resolution: "@napi-rs/canvas-linux-arm64-musl@npm:0.1.29"
+"@napi-rs/canvas-linux-arm64-musl@npm:0.1.30":
+ version: 0.1.30
+ resolution: "@napi-rs/canvas-linux-arm64-musl@npm:0.1.30"
conditions: os=linux & cpu=arm64 & libc=musl
languageName: node
linkType: hard
-"@napi-rs/canvas-linux-x64-gnu@npm:0.1.29":
- version: 0.1.29
- resolution: "@napi-rs/canvas-linux-x64-gnu@npm:0.1.29"
+"@napi-rs/canvas-linux-x64-gnu@npm:0.1.30":
+ version: 0.1.30
+ resolution: "@napi-rs/canvas-linux-x64-gnu@npm:0.1.30"
conditions: os=linux & cpu=x64 & libc=glibc
languageName: node
linkType: hard
-"@napi-rs/canvas-linux-x64-musl@npm:0.1.29":
- version: 0.1.29
- resolution: "@napi-rs/canvas-linux-x64-musl@npm:0.1.29"
+"@napi-rs/canvas-linux-x64-musl@npm:0.1.30":
+ version: 0.1.30
+ resolution: "@napi-rs/canvas-linux-x64-musl@npm:0.1.30"
conditions: os=linux & cpu=x64 & libc=musl
languageName: node
linkType: hard
-"@napi-rs/canvas-win32-x64-msvc@npm:0.1.29":
- version: 0.1.29
- resolution: "@napi-rs/canvas-win32-x64-msvc@npm:0.1.29"
+"@napi-rs/canvas-win32-x64-msvc@npm:0.1.30":
+ version: 0.1.30
+ resolution: "@napi-rs/canvas-win32-x64-msvc@npm:0.1.30"
conditions: os=win32 & cpu=x64
languageName: node
linkType: hard
-"@napi-rs/canvas@npm:^0.1.29":
- version: 0.1.29
- resolution: "@napi-rs/canvas@npm:0.1.29"
+"@napi-rs/canvas@npm:^0.1.30":
+ version: 0.1.30
+ resolution: "@napi-rs/canvas@npm:0.1.30"
dependencies:
- "@napi-rs/canvas-android-arm64": 0.1.29
- "@napi-rs/canvas-darwin-arm64": 0.1.29
- "@napi-rs/canvas-darwin-x64": 0.1.29
- "@napi-rs/canvas-linux-arm-gnueabihf": 0.1.29
- "@napi-rs/canvas-linux-arm64-gnu": 0.1.29
- "@napi-rs/canvas-linux-arm64-musl": 0.1.29
- "@napi-rs/canvas-linux-x64-gnu": 0.1.29
- "@napi-rs/canvas-linux-x64-musl": 0.1.29
- "@napi-rs/canvas-win32-x64-msvc": 0.1.29
+ "@napi-rs/canvas-android-arm64": 0.1.30
+ "@napi-rs/canvas-darwin-arm64": 0.1.30
+ "@napi-rs/canvas-darwin-x64": 0.1.30
+ "@napi-rs/canvas-linux-arm-gnueabihf": 0.1.30
+ "@napi-rs/canvas-linux-arm64-gnu": 0.1.30
+ "@napi-rs/canvas-linux-arm64-musl": 0.1.30
+ "@napi-rs/canvas-linux-x64-gnu": 0.1.30
+ "@napi-rs/canvas-linux-x64-musl": 0.1.30
+ "@napi-rs/canvas-win32-x64-msvc": 0.1.30
dependenciesMeta:
"@napi-rs/canvas-android-arm64":
optional: true
@@ -214,7 +221,7 @@ __metadata:
optional: true
"@napi-rs/canvas-win32-x64-msvc":
optional: true
- checksum: 1a8a61429f2be2c975e5e543f6a79c2d1762acfe85a87d308e156b5cbcf4d0d60649fb374128888f465b09563bc96ef91c14c2c9b6c4dd21e1c1acf22c000737
+ checksum: ee5e6f308a530daf1df85d4fe03877f8d12e06ed00c36ca128166832dd7eefd2c0481c8031a4150688e32cf96838719d93a55c2e1f0a17feb012ce6981c0ab08
languageName: node
linkType: hard
@@ -245,17 +252,12 @@ __metadata:
languageName: node
linkType: hard
-"@notenoughupdates/discord.js-minesweeper@npm:^1.0.10":
- version: 1.0.10
- resolution: "@notenoughupdates/discord.js-minesweeper@npm:1.0.10"
- checksum: f9467e8f78c825c058098c32b4f7e1e9fca2a3ce90536363d716de2849a1402d32ea8a17c0e188af0fb9f1851174661deacf82d64705dc92306d634dad5c57c5
- languageName: node
- linkType: hard
-
-"@notenoughupdates/events-intercept@npm:^3.0.1":
- version: 3.0.1
- resolution: "@notenoughupdates/events-intercept@npm:3.0.1"
- checksum: cd1f8d608160276c35d0cfe5116181bc34c5017b1e2f785e868d16b8983ed434abbc12f1d090bc5e5ced26c9460aea457bac92a919f4efda14db246a5392c62e
+"@notenoughupdates/discord-akairo@npm:^10.0.0-dev.1664158089.48d6368":
+ version: 10.0.0-dev.1664158089.48d6368
+ resolution: "@notenoughupdates/discord-akairo@npm:10.0.0-dev.1664158089.48d6368"
+ dependencies:
+ zod: ^3.19.1
+ checksum: d07d3d554f4bd45663339275d93b795506da65be592cdf50ee75bd1fd239d2dc574d36107f1406fffaf0ecb2649d38839b3ac9c9684c9966ae06ff83058a6557
languageName: node
linkType: hard
@@ -266,20 +268,6 @@ __metadata:
languageName: node
linkType: hard
-"@notenoughupdates/simplify-number@npm:^1.0.1":
- version: 1.0.1
- resolution: "@notenoughupdates/simplify-number@npm:1.0.1"
- checksum: 91b73abf024888fdf68954dfc46464f6e22f0f83291bae7f75f223b49d115f23be0aad809a72a0dba10012418e1562a9703795c2ec084edd37f52dca16649141
- languageName: node
- linkType: hard
-
-"@notenoughupdates/wolfram-alpha-api@npm:^1.0.2":
- version: 1.0.2
- resolution: "@notenoughupdates/wolfram-alpha-api@npm:1.0.2"
- checksum: 6aee1d5c2fc13393fb7d8d9e6ffa0c688f9a1f9c44f012a3042778384afbb5c777df7c9ec699f6e45b24326c3d12919302453085c17ce28dbc89717c3353f86d
- languageName: node
- linkType: hard
-
"@npmcli/fs@npm:^2.1.0":
version: 2.1.2
resolution: "@npmcli/fs@npm:2.1.2"
@@ -308,12 +296,12 @@ __metadata:
linkType: hard
"@sapphire/shapeshift@npm:^3.5.1":
- version: 3.5.1
- resolution: "@sapphire/shapeshift@npm:3.5.1"
+ version: 3.6.0
+ resolution: "@sapphire/shapeshift@npm:3.6.0"
dependencies:
fast-deep-equal: ^3.1.3
lodash.uniqwith: ^4.5.0
- checksum: caecfef844c9e43e921a5051da888fae7da8980bfd9f9bb4f7fee85931d40929ffb9b6dfae464c0dccee61e56f7698f998e4d9a54d25f35fad39a51ba1a4f391
+ checksum: 31b426424d064c516144c6eda07dfa0e44d7cbb8309dde919b923aa6ae939faac6384fa4d08db391a8da11efa3a83c18c9be1ebd053ba29403e61f5e2450b788
languageName: node
linkType: hard
@@ -324,83 +312,118 @@ __metadata:
languageName: node
linkType: hard
-"@sentry/core@npm:7.11.1":
- version: 7.11.1
- resolution: "@sentry/core@npm:7.11.1"
+"@sentry/core@npm:7.13.0":
+ version: 7.13.0
+ resolution: "@sentry/core@npm:7.13.0"
dependencies:
- "@sentry/hub": 7.11.1
- "@sentry/types": 7.11.1
- "@sentry/utils": 7.11.1
+ "@sentry/hub": 7.13.0
+ "@sentry/types": 7.13.0
+ "@sentry/utils": 7.13.0
tslib: ^1.9.3
- checksum: 4e3fa11d248182a6cdce87ff60111cd29fe028fb84abed7f362f3d7b1a6db9b97bf6bf07317f2338fce01b331a1e867a34e3ef477134b859270ef0d0f48bdc8e
+ checksum: 8fd5b0eab630a54ea1beec1b3fe7deb388e95ca3312c1f0eaffa32090882ca7792287b5e7d157fc1c408a0ec1bfb769ac45a77a5385068dcd8fc6f3e6949f8a1
languageName: node
linkType: hard
-"@sentry/hub@npm:7.11.1":
- version: 7.11.1
- resolution: "@sentry/hub@npm:7.11.1"
+"@sentry/hub@npm:7.13.0":
+ version: 7.13.0
+ resolution: "@sentry/hub@npm:7.13.0"
dependencies:
- "@sentry/types": 7.11.1
- "@sentry/utils": 7.11.1
+ "@sentry/types": 7.13.0
+ "@sentry/utils": 7.13.0
tslib: ^1.9.3
- checksum: 1df55e6e3a494167e6b1592f1aa6ea185feeed3a68d9060340877b3db5943fe45437c5d508dfabc1d4275ce7f3c3910f3bb4ad1880a3c9d01a7d07200f3feb91
+ checksum: 690f1eecd4d9f0a87ca4344b551b990df234ec7197b21175293fb713f917c6171ed44f35042af5b83a0bae5e0963a520490bfd905d48bd040a2f2532247e04d6
languageName: node
linkType: hard
-"@sentry/integrations@npm:^7.11.1":
- version: 7.11.1
- resolution: "@sentry/integrations@npm:7.11.1"
+"@sentry/integrations@npm:^7.13.0":
+ version: 7.13.0
+ resolution: "@sentry/integrations@npm:7.13.0"
dependencies:
- "@sentry/types": 7.11.1
- "@sentry/utils": 7.11.1
+ "@sentry/types": 7.13.0
+ "@sentry/utils": 7.13.0
localforage: ^1.8.1
tslib: ^1.9.3
- checksum: e89ab412462e4d93a6689360d3afe2eb5e64a45f3d2bf9e8c3cdb8f71bfe66b71b62ac1d867d9c726c4d2e1ab9309893bb7f856f74acbc382debe60db33008fa
+ checksum: b952043a97c60ee157fe734de6a44dcdd1d2175d5810122b0703f9a8e0999948f048042f5a8bb35efdd7a29ee1c177cfd99f1102e0797a0c2e5b62ee790c1c89
languageName: node
linkType: hard
-"@sentry/node@npm:^7.11.1":
- version: 7.11.1
- resolution: "@sentry/node@npm:7.11.1"
+"@sentry/node@npm:^7.13.0":
+ version: 7.13.0
+ resolution: "@sentry/node@npm:7.13.0"
dependencies:
- "@sentry/core": 7.11.1
- "@sentry/hub": 7.11.1
- "@sentry/types": 7.11.1
- "@sentry/utils": 7.11.1
+ "@sentry/core": 7.13.0
+ "@sentry/hub": 7.13.0
+ "@sentry/types": 7.13.0
+ "@sentry/utils": 7.13.0
cookie: ^0.4.1
https-proxy-agent: ^5.0.0
lru_map: ^0.3.3
tslib: ^1.9.3
- checksum: 824780c2d4fecbfaabfacd27b7108a21c6e37b98a61aeb2dda394dae6d67584ef46a749df80fb7dfa3e43bd4e6dcb28b7bcf8a83c77ebef621d05f231651724a
+ checksum: 36de86c7bb8e62fe93c0cc72dfbd0d77925ef18b6abd98a034b676853c9cca705be276fee617ddcedbf89659454055cd79ab82f3f7b77d465617810787d8775d
languageName: node
linkType: hard
-"@sentry/tracing@npm:^7.11.1":
- version: 7.11.1
- resolution: "@sentry/tracing@npm:7.11.1"
+"@sentry/tracing@npm:^7.13.0":
+ version: 7.13.0
+ resolution: "@sentry/tracing@npm:7.13.0"
dependencies:
- "@sentry/hub": 7.11.1
- "@sentry/types": 7.11.1
- "@sentry/utils": 7.11.1
+ "@sentry/hub": 7.13.0
+ "@sentry/types": 7.13.0
+ "@sentry/utils": 7.13.0
tslib: ^1.9.3
- checksum: c0c4b540eff30deb94b939d7792f765410bd0abb3c495a49cd89c1ed113f0ca46fb7b12bdc777ddb42f64018a5647afe69bb444d77a2e0cb8a8ae9ed813a7f7b
+ checksum: 4d51a166b74799a85bfef9e5027147bec2ef977bd50e820773a8d9a8f6f2658c97b40ce67501f7a3f1406d30da64f38454d903fdf98e81d4da30b70fc63aca27
languageName: node
linkType: hard
-"@sentry/types@npm:7.11.1, @sentry/types@npm:^7.11.1":
- version: 7.11.1
- resolution: "@sentry/types@npm:7.11.1"
- checksum: 935dbd83d8c43bca202979fef12fe2af0508e44c61a0b3b2e10971006b59938fac36bfde530c7b7db14601dcbb17a2a7b35f479de8bbfe961df3eff7fd9327ce
+"@sentry/types@npm:7.13.0, @sentry/types@npm:^7.13.0":
+ version: 7.13.0
+ resolution: "@sentry/types@npm:7.13.0"
+ checksum: 8bd94d1cf735af61a3cea77e7e925e487dc84b925fa1e1a0aa9a566096e5d99d3bb72c6ea2f03c20d7894824f35edbb8b25352b3a1c78e62729a77a93a1abf71
languageName: node
linkType: hard
-"@sentry/utils@npm:7.11.1":
- version: 7.11.1
- resolution: "@sentry/utils@npm:7.11.1"
+"@sentry/utils@npm:7.13.0":
+ version: 7.13.0
+ resolution: "@sentry/utils@npm:7.13.0"
dependencies:
- "@sentry/types": 7.11.1
+ "@sentry/types": 7.13.0
tslib: ^1.9.3
- checksum: e0a1d8528e9f99a35c88786cc230a5466966a59554796bbf13a33aa8956911c8bce7c556bb7a90ba20c9af9fa64ef6b87b956d1d8bae6ff42950ce4125c3b44e
+ checksum: e655e2bd444c9f8aedac4bc52e9a75bf74ef0086ffb1b9efc9cf6670aab9b0deca45e9d7c808e7d19e51ff4b40bcd178b6c5b2ea55e8cfb81da630db6b75bfe2
+ languageName: node
+ linkType: hard
+
+"@tanzanite/deep-lock@npm:^1.1.1":
+ version: 1.1.1
+ resolution: "@tanzanite/deep-lock@npm:1.1.1"
+ checksum: cde199ae80726ebe560c46e15fec852da8a00257affe4fc575048261b6f6db165f49dde308bbfadd91d0bc088e9efa93845ed92dc88a67dc35b1353797e14e1b
+ languageName: node
+ linkType: hard
+
+"@tanzanite/discord.js-minesweeper@npm:^1.2.0":
+ version: 1.2.0
+ resolution: "@tanzanite/discord.js-minesweeper@npm:1.2.0"
+ checksum: 6612b41bd4b46f581e5ab00dc102c96d96eac731089708e5b3080b2d9fc14993ca4dd3ddb3e8b0f51339e72159d9fe27f39d0b4fe62adb014e7b909ee4d39a29
+ languageName: node
+ linkType: hard
+
+"@tanzanite/events-intercept@npm:^3.1.0":
+ version: 3.1.0
+ resolution: "@tanzanite/events-intercept@npm:3.1.0"
+ checksum: f76a6ac1b91348278a0b526ee7467b33596fd1a4a0bdfbb29e0a15407106dba1b5ccd1dd4bf24c2032f93548a31df1551d76b694410c76dbe8bec45f9435c580
+ languageName: node
+ linkType: hard
+
+"@tanzanite/simplify-number@npm:^2.0.1":
+ version: 2.0.1
+ resolution: "@tanzanite/simplify-number@npm:2.0.1"
+ checksum: 8061f944340e2599386dea30254fc363e5aed6dd17279508fec42d6c49e70858a56e1106b30b784589fa92616126a3932c51b79d37ac86f6d917e93389f0ddce
+ languageName: node
+ linkType: hard
+
+"@tanzanite/wolfram-alpha@npm:^1.1.0":
+ version: 1.1.0
+ resolution: "@tanzanite/wolfram-alpha@npm:1.1.0"
+ checksum: 35bf790a2fa0e0964766eae3da643b8af254de7f94ee1ae3d52d2ac0138132895598a0a34abaacf769cac615155ea78cb403ebd16f7680c6086f7cdbf8936678
languageName: node
linkType: hard
@@ -480,35 +503,25 @@ __metadata:
linkType: hard
"@types/express-serve-static-core@npm:^4.17.18":
- version: 4.17.30
- resolution: "@types/express-serve-static-core@npm:4.17.30"
+ version: 4.17.31
+ resolution: "@types/express-serve-static-core@npm:4.17.31"
dependencies:
"@types/node": "*"
"@types/qs": "*"
"@types/range-parser": "*"
- checksum: c40d9027884ab9e97fa29d9d41d1b75a5966109312e26594cf03c61b278b5bf8e095f53589e47899b34a2e224291a44043617695c3e8bd22284f988e48582ee6
+ checksum: 009bfbe1070837454a1056aa710d0390ee5fb8c05dfe5a1691cc3e2ca88dc256f80e1ca27cb51a978681631d2f6431bfc9ec352ea46dd0c6eb183d0170bde5df
languageName: node
linkType: hard
-"@types/express@npm:^4.17.13":
- version: 4.17.13
- resolution: "@types/express@npm:4.17.13"
+"@types/express@npm:^4.17.14":
+ version: 4.17.14
+ resolution: "@types/express@npm:4.17.14"
dependencies:
"@types/body-parser": "*"
"@types/express-serve-static-core": ^4.17.18
"@types/qs": "*"
"@types/serve-static": "*"
- checksum: 12a2a0e6c4b993fc0854bec665906788aea0d8ee4392389d7a98a5de1eefdd33c9e1e40a91f3afd274011119c506f7b4126acb97fae62ae20b654974d44cba12
- languageName: node
- linkType: hard
-
-"@types/glob@npm:*":
- version: 7.2.0
- resolution: "@types/glob@npm:7.2.0"
- dependencies:
- "@types/minimatch": "*"
- "@types/node": "*"
- checksum: 6ae717fedfdfdad25f3d5a568323926c64f52ef35897bcac8aca8e19bc50c0bd84630bbd063e5d52078b2137d8e7d3c26eabebd1a2f03ff350fff8a91e79fc19
+ checksum: 15c1af46d02de834e4a225eccaa9d85c0370fdbb3ed4e1bc2d323d24872309961542b993ae236335aeb3e278630224a6ea002078d39e651d78a3b0356b1eaa79
languageName: node
linkType: hard
@@ -519,10 +532,19 @@ __metadata:
languageName: node
linkType: hard
-"@types/lodash@npm:^4.14.184":
- version: 4.14.184
- resolution: "@types/lodash@npm:4.14.184"
- checksum: 6d9a4d67f7f9d0ec3fd21174f3dd3d00629dc1227eb469450eace53adbc1f7e2330699c28d0fe093e5f0fef0f0e763098be1f779268857213224af082b62be21
+"@types/lodash-es@npm:^4":
+ version: 4.17.6
+ resolution: "@types/lodash-es@npm:4.17.6"
+ dependencies:
+ "@types/lodash": "*"
+ checksum: 9bd239dd525086e278821949ce12fbdd4f100a060fed9323fc7ad5661113e1641f28a7ebab617230ed3474680d8f4de705c1928b48252bb684be6ec9eed715db
+ languageName: node
+ linkType: hard
+
+"@types/lodash@npm:*":
+ version: 4.14.185
+ resolution: "@types/lodash@npm:4.14.185"
+ checksum: f81d13da5ecab110ca9c5c7cc2bedc3c9802a6acf668576aecd1b8f4b134ed81d06c15f1e600fb08f05975098280a0d97d30cddfc2cb39ec1c6b56e971ca53b3
languageName: node
linkType: hard
@@ -533,13 +555,6 @@ __metadata:
languageName: node
linkType: hard
-"@types/minimatch@npm:*":
- version: 5.1.0
- resolution: "@types/minimatch@npm:5.1.0"
- checksum: 041c1bf29a9c3d29ac401380cf94fa79613c8fccaa5b9e763996159e504bda4cb11e80a638f7842a987590f232864ba84a19f9b803d433cd92bac2759696dd24
- languageName: node
- linkType: hard
-
"@types/ms@npm:*":
version: 0.7.31
resolution: "@types/ms@npm:0.7.31"
@@ -547,10 +562,20 @@ __metadata:
languageName: node
linkType: hard
-"@types/node@npm:*, @types/node@npm:^18.7.13":
- version: 18.7.13
- resolution: "@types/node@npm:18.7.13"
- checksum: 45431e7e89ecaf85c7d2c180d801c132a7c59e2f8ad578726b6d71cc74e3267c18f9ccdcad738bc0479790c078f0c79efb0e58da2c6be535c15995dbb19050c9
+"@types/node-fetch@npm:^2.6.2":
+ version: 2.6.2
+ resolution: "@types/node-fetch@npm:2.6.2"
+ dependencies:
+ "@types/node": "*"
+ form-data: ^3.0.0
+ checksum: 6f73b1470000d303d25a6fb92875ea837a216656cb7474f66cdd67bb014aa81a5a11e7ac9c21fe19bee9ecb2ef87c1962bceeaec31386119d1ac86e4c30ad7a6
+ languageName: node
+ linkType: hard
+
+"@types/node@npm:*, @types/node@npm:^18.7.21":
+ version: 18.7.21
+ resolution: "@types/node@npm:18.7.21"
+ checksum: 9e0558dd44766fb3b1b26815e9877849d8f1188115e0d2bee540cee2c5a11f90e4c00ee059edae8ea018e7f66217e4bf53271536c9a6fd05e33f713b8daa4c66
languageName: node
linkType: hard
@@ -572,10 +597,10 @@ __metadata:
languageName: node
linkType: hard
-"@types/prettier@npm:^2.7.0":
- version: 2.7.0
- resolution: "@types/prettier@npm:2.7.0"
- checksum: bf5d0c7c1270909b39399539ac106d20ddaa85fe92eb1d59922dc99159604b4f8d5e41b0045fb29c8011585cf5bca2350b7441ef3d9816c08bd0e10ebd4b31d4
+"@types/prettier@npm:^2.7.1":
+ version: 2.7.1
+ resolution: "@types/prettier@npm:2.7.1"
+ checksum: 5e3f58e229d6c73b5f5cae2e8f96c1c4a5b5805f83459e17a045ba8e96152b1d38e86b63e3172fb159dac923388699660862b75b2d37e54220805f0e691e26f1
languageName: node
linkType: hard
@@ -593,16 +618,6 @@ __metadata:
languageName: node
linkType: hard
-"@types/rimraf@npm:^3.0.2":
- version: 3.0.2
- resolution: "@types/rimraf@npm:3.0.2"
- dependencies:
- "@types/glob": "*"
- "@types/node": "*"
- checksum: b47fa302f46434cba704d20465861ad250df79467d3d289f9d6490d3aeeb41e8cb32dd80bd1a8fd833d1e185ac719fbf9be12e05ad9ce9be094d8ee8f1405347
- languageName: node
- linkType: hard
-
"@types/serve-static@npm:*":
version: 1.15.0
resolution: "@types/serve-static@npm:1.15.0"
@@ -620,10 +635,10 @@ __metadata:
languageName: node
linkType: hard
-"@types/validator@npm:^13.7.1, @types/validator@npm:^13.7.5":
- version: 13.7.6
- resolution: "@types/validator@npm:13.7.6"
- checksum: f860dd87bc5f90cc33d2802cf2a4da307ddac63c86d86b858a85dd62d457c8fa42fc8756e05b5d24e741376debc13d46ed14bc700006bf7d0cb910118022492b
+"@types/validator@npm:^13.7.1, @types/validator@npm:^13.7.7":
+ version: 13.7.7
+ resolution: "@types/validator@npm:13.7.7"
+ checksum: e32d2bc3b86317da2dff7565e371a2bd0108cdbd7c0b426070c9b9fab30cf07572eea4fb193cb7420261b2eb99b2fc112bf021d48f98eee181844a47533f817a
languageName: node
linkType: hard
@@ -636,15 +651,14 @@ __metadata:
languageName: node
linkType: hard
-"@typescript-eslint/eslint-plugin@npm:^5.35.1":
- version: 5.35.1
- resolution: "@typescript-eslint/eslint-plugin@npm:5.35.1"
+"@typescript-eslint/eslint-plugin@npm:^5.38.0":
+ version: 5.38.0
+ resolution: "@typescript-eslint/eslint-plugin@npm:5.38.0"
dependencies:
- "@typescript-eslint/scope-manager": 5.35.1
- "@typescript-eslint/type-utils": 5.35.1
- "@typescript-eslint/utils": 5.35.1
+ "@typescript-eslint/scope-manager": 5.38.0
+ "@typescript-eslint/type-utils": 5.38.0
+ "@typescript-eslint/utils": 5.38.0
debug: ^4.3.4
- functional-red-black-tree: ^1.0.1
ignore: ^5.2.0
regexpp: ^3.2.0
semver: ^7.3.7
@@ -655,53 +669,54 @@ __metadata:
peerDependenciesMeta:
typescript:
optional: true
- checksum: 073f4dffd863881f1c87e1c217ac13bda44aaa2db12ef260032b5e8eb6ffd6b9cf6f62c85132dbf84152f353c435c66dd4f75c3bcb86eb23e926737aa4fb66fa
+ checksum: e9cd1970c7c8a438aee912cf00aa27bdcde0a0fb57bbfe70eccda93eefa5b4fb4c7ebf5ba7a51744c1ec2b4df3a72b8dcd19dc17a9c3e4e3435f631ac6b10a6a
languageName: node
linkType: hard
"@typescript-eslint/experimental-utils@npm:^5.0.0":
- version: 5.35.1
- resolution: "@typescript-eslint/experimental-utils@npm:5.35.1"
+ version: 5.38.0
+ resolution: "@typescript-eslint/experimental-utils@npm:5.38.0"
dependencies:
- "@typescript-eslint/utils": 5.35.1
+ "@typescript-eslint/utils": 5.38.0
peerDependencies:
eslint: ^6.0.0 || ^7.0.0 || ^8.0.0
- checksum: b67f347e45e719080ac6460c7624db2d1eb1c02abd1d031cfb96f2b0cd8a0cfff3cec71a3913fd0da20c045ec9e0b888e3ef1e50bcb606e2644b8e4f91cce1c5
+ checksum: c1cf9c74550ff2e9f988c15ca343625037c522583017e1b97f56a19d2c539b617934f34ce7aaa323ea4d26408410a761eea4e4e34c9036a270070c49e44d2571
languageName: node
linkType: hard
-"@typescript-eslint/parser@npm:^5.35.1":
- version: 5.35.1
- resolution: "@typescript-eslint/parser@npm:5.35.1"
+"@typescript-eslint/parser@npm:^5.38.0":
+ version: 5.38.0
+ resolution: "@typescript-eslint/parser@npm:5.38.0"
dependencies:
- "@typescript-eslint/scope-manager": 5.35.1
- "@typescript-eslint/types": 5.35.1
- "@typescript-eslint/typescript-estree": 5.35.1
+ "@typescript-eslint/scope-manager": 5.38.0
+ "@typescript-eslint/types": 5.38.0
+ "@typescript-eslint/typescript-estree": 5.38.0
debug: ^4.3.4
peerDependencies:
eslint: ^6.0.0 || ^7.0.0 || ^8.0.0
peerDependenciesMeta:
typescript:
optional: true
- checksum: 57ea1a1da60b370f8d5c11c86155f7339359a90f2c59e34c89f626f1a79cb440248f07bd307a27ebbbcc997d2731cb9754cdbc37639770940521a938dd89870c
+ checksum: d5fb2d8f3a25cd6ff31326c665db4617f2d428247cad690f0404de440abbcfc7261528f54d642d2b121aae34aadecb55a24b72c8ef341cafdc7b2bbcbf7dae8d
languageName: node
linkType: hard
-"@typescript-eslint/scope-manager@npm:5.35.1":
- version: 5.35.1
- resolution: "@typescript-eslint/scope-manager@npm:5.35.1"
+"@typescript-eslint/scope-manager@npm:5.38.0":
+ version: 5.38.0
+ resolution: "@typescript-eslint/scope-manager@npm:5.38.0"
dependencies:
- "@typescript-eslint/types": 5.35.1
- "@typescript-eslint/visitor-keys": 5.35.1
- checksum: 5a969a081309bac5962f99ee6dfdfd9c68ea677bc79d9796592dce82a36217f67aa55c7bf421b2c97b46c5149d6a9401bb4c57829595e8c19f47cfa9e8c2dd86
+ "@typescript-eslint/types": 5.38.0
+ "@typescript-eslint/visitor-keys": 5.38.0
+ checksum: a34d2976e9c755b853b6524e0b9fb1da237340ddff9f6839a51ba37998527c02d0f2f16ffc3d4baa47898f2bb7eb85a6749d6ca588c0461dbd654d8f9925dd0f
languageName: node
linkType: hard
-"@typescript-eslint/type-utils@npm:5.35.1":
- version: 5.35.1
- resolution: "@typescript-eslint/type-utils@npm:5.35.1"
+"@typescript-eslint/type-utils@npm:5.38.0":
+ version: 5.38.0
+ resolution: "@typescript-eslint/type-utils@npm:5.38.0"
dependencies:
- "@typescript-eslint/utils": 5.35.1
+ "@typescript-eslint/typescript-estree": 5.38.0
+ "@typescript-eslint/utils": 5.38.0
debug: ^4.3.4
tsutils: ^3.21.0
peerDependencies:
@@ -709,23 +724,23 @@ __metadata:
peerDependenciesMeta:
typescript:
optional: true
- checksum: af317ba156f2767f76a7f97193873a00468370e157fdcc6ac19f664bc6c4c0a6836bd25028d17fdd54d339b6842fda68b82f1ce4142a222de6953625ea6c0a9c
+ checksum: 43f2f55329b2357bedf158a93a469d058a11c69f8f88ff891080b8cb5977bffe8d679923bce7048cbc076c083e0f5741c83b761355309d606cc4e217e1da4208
languageName: node
linkType: hard
-"@typescript-eslint/types@npm:5.35.1":
- version: 5.35.1
- resolution: "@typescript-eslint/types@npm:5.35.1"
- checksum: a4e1001867f43f3364b109fc5a07b91ae7a34b78ab191c6c5c4695dac9bb2b80b0a602651c0b807c1c7c1fc3656d2bbd47c637afa08a09e7b1c39eae3c489e00
+"@typescript-eslint/types@npm:5.38.0":
+ version: 5.38.0
+ resolution: "@typescript-eslint/types@npm:5.38.0"
+ checksum: 03aec1de64417e60830c6d33bb4f1bf4402411080371013513f55c7a2fadb6f8745a89a7604cde03d89aa53307f94bc913060c5897ed93285247e4c39af43a00
languageName: node
linkType: hard
-"@typescript-eslint/typescript-estree@npm:5.35.1":
- version: 5.35.1
- resolution: "@typescript-eslint/typescript-estree@npm:5.35.1"
+"@typescript-eslint/typescript-estree@npm:5.38.0":
+ version: 5.38.0
+ resolution: "@typescript-eslint/typescript-estree@npm:5.38.0"
dependencies:
- "@typescript-eslint/types": 5.35.1
- "@typescript-eslint/visitor-keys": 5.35.1
+ "@typescript-eslint/types": 5.38.0
+ "@typescript-eslint/visitor-keys": 5.38.0
debug: ^4.3.4
globby: ^11.1.0
is-glob: ^4.0.3
@@ -734,33 +749,33 @@ __metadata:
peerDependenciesMeta:
typescript:
optional: true
- checksum: a917ca4753a3f92c8d8555c96f5414383a9742761625476fa36a019401543aa74996159afa0f7fc7fae05fe0f904e3c6f4153a55412070c8a94e8171e81084c7
+ checksum: 174461c91e49a0340945da2d31e38ec175cd90b2b5068f3c925518cc9182100fe1435d3225908a52f62257e97bc2b995cbc6b6bd1b7143ff0a0e4b483bd70834
languageName: node
linkType: hard
-"@typescript-eslint/utils@npm:5.35.1":
- version: 5.35.1
- resolution: "@typescript-eslint/utils@npm:5.35.1"
+"@typescript-eslint/utils@npm:5.38.0":
+ version: 5.38.0
+ resolution: "@typescript-eslint/utils@npm:5.38.0"
dependencies:
"@types/json-schema": ^7.0.9
- "@typescript-eslint/scope-manager": 5.35.1
- "@typescript-eslint/types": 5.35.1
- "@typescript-eslint/typescript-estree": 5.35.1
+ "@typescript-eslint/scope-manager": 5.38.0
+ "@typescript-eslint/types": 5.38.0
+ "@typescript-eslint/typescript-estree": 5.38.0
eslint-scope: ^5.1.1
eslint-utils: ^3.0.0
peerDependencies:
eslint: ^6.0.0 || ^7.0.0 || ^8.0.0
- checksum: 2b04092583c3139dd090727c24fb9d7fdb1fb9f20f2e3f0141cab5b98b6a1934b0fc8cab948f7faae55588385b0f1fb7bbf91f52c705ce4528036a527c3119c6
+ checksum: c927a68d4ff5029ed3dbc7e6e87702f7cdfba26452ccf401b37cc68f6e5cca72eb884831dbc7957512998d59950b1852b2ecea19f174a20fe659d851b4afd4fd
languageName: node
linkType: hard
-"@typescript-eslint/visitor-keys@npm:5.35.1":
- version: 5.35.1
- resolution: "@typescript-eslint/visitor-keys@npm:5.35.1"
+"@typescript-eslint/visitor-keys@npm:5.38.0":
+ version: 5.38.0
+ resolution: "@typescript-eslint/visitor-keys@npm:5.38.0"
dependencies:
- "@typescript-eslint/types": 5.35.1
+ "@typescript-eslint/types": 5.38.0
eslint-visitor-keys: ^3.3.0
- checksum: ef3c8377aac89935b5cc2fcf37bb3e42aa5f98848e7c22bdcbe5bb06c0fe8a1373a6897fd21109be8929b4708ad06c8874d2ef7bba17ff64911964203457330d
+ checksum: cc3d0c6eb0c9a20a25d66b640d759cb1b52f8df485f16d948218d63d798b5c0672ef298f5dae5e5327ec021c0f8369d1da5d26b9c16a245a20fa44a9365956bc
languageName: node
linkType: hard
@@ -899,6 +914,13 @@ __metadata:
languageName: node
linkType: hard
+"asynckit@npm:^0.4.0":
+ version: 0.4.0
+ resolution: "asynckit@npm:0.4.0"
+ checksum: 7b78c451df768adba04e2d02e63e2d0bf3b07adcd6e42b4cf665cb7ce899bedd344c69a1dcbce355b5f972d597b25aaa1c1742b52cffd9caccb22f348114f6be
+ languageName: node
+ linkType: hard
+
"balanced-match@npm:^1.0.0":
version: 1.0.2
resolution: "balanced-match@npm:1.0.2"
@@ -906,7 +928,7 @@ __metadata:
languageName: node
linkType: hard
-"base64-js@npm:^1.3.0, base64-js@npm:^1.3.1":
+"base64-js@npm:^1.3.0":
version: 1.5.1
resolution: "base64-js@npm:1.5.1"
checksum: 669632eb3745404c2f822a18fc3a0122d2f9a7a13f7fb8b5823ee19d1d2ff9ee5b52c53367176ea4ad093c332fd5ab4bd0ebae5a8e27917a4105a4cfc86b1005
@@ -920,16 +942,6 @@ __metadata:
languageName: node
linkType: hard
-"bl@npm:^1.0.0":
- version: 1.2.3
- resolution: "bl@npm:1.2.3"
- dependencies:
- readable-stream: ^2.3.5
- safe-buffer: ^5.1.1
- checksum: 123f097989ce2fa9087ce761cd41176aaaec864e28f7dfe5c7dab8ae16d66d9844f849c3ad688eb357e3c5e4f49b573e3c0780bb8bc937206735a3b6f8569a5f
- languageName: node
- linkType: hard
-
"brace-expansion@npm:^1.1.7":
version: 1.1.11
resolution: "brace-expansion@npm:1.1.11"
@@ -958,30 +970,6 @@ __metadata:
languageName: node
linkType: hard
-"buffer-alloc-unsafe@npm:^1.1.0":
- version: 1.1.0
- resolution: "buffer-alloc-unsafe@npm:1.1.0"
- checksum: c5e18bf51f67754ec843c9af3d4c005051aac5008a3992938dda1344e5cfec77c4b02b4ca303644d1e9a6e281765155ce6356d85c6f5ccc5cd21afc868def396
- languageName: node
- linkType: hard
-
-"buffer-alloc@npm:^1.2.0":
- version: 1.2.0
- resolution: "buffer-alloc@npm:1.2.0"
- dependencies:
- buffer-alloc-unsafe: ^1.1.0
- buffer-fill: ^1.0.0
- checksum: 560cd27f3cbe73c614867da373407d4506309c62fe18de45a1ce191f3785ec6ca2488d802ff82065798542422980ca25f903db078c57822218182c37c3576df5
- languageName: node
- linkType: hard
-
-"buffer-crc32@npm:~0.2.3":
- version: 0.2.13
- resolution: "buffer-crc32@npm:0.2.13"
- checksum: 06252347ae6daca3453b94e4b2f1d3754a3b146a111d81c68924c22d91889a40623264e95e67955b1cb4a68cbedf317abeabb5140a9766ed248973096db5ce1c
- languageName: node
- linkType: hard
-
"buffer-equal-constant-time@npm:1.0.1":
version: 1.0.1
resolution: "buffer-equal-constant-time@npm:1.0.1"
@@ -989,13 +977,6 @@ __metadata:
languageName: node
linkType: hard
-"buffer-fill@npm:^1.0.0":
- version: 1.0.0
- resolution: "buffer-fill@npm:1.0.0"
- checksum: c29b4723ddeab01e74b5d3b982a0c6828f2ded49cef049ddca3dac661c874ecdbcecb5dd8380cf0f4adbeb8cff90a7de724126750a1f1e5ebd4eb6c59a1315b1
- languageName: node
- linkType: hard
-
"buffer-writer@npm:2.0.0":
version: 2.0.0
resolution: "buffer-writer@npm:2.0.0"
@@ -1003,16 +984,6 @@ __metadata:
languageName: node
linkType: hard
-"buffer@npm:^5.2.1":
- version: 5.7.1
- resolution: "buffer@npm:5.7.1"
- dependencies:
- base64-js: ^1.3.1
- ieee754: ^1.1.13
- checksum: e2cf8429e1c4c7b8cbd30834ac09bd61da46ce35f5c22a78e6c2f04497d6d25541b16881e30a019c6fd3154150650ccee27a308eff3e26229d788bbdeb08ab84
- languageName: node
- linkType: hard
-
"cacache@npm:^16.1.0":
version: 16.1.3
resolution: "cacache@npm:16.1.3"
@@ -1134,10 +1105,12 @@ __metadata:
languageName: node
linkType: hard
-"commander@npm:^2.8.1":
- version: 2.20.3
- resolution: "commander@npm:2.20.3"
- checksum: ab8c07884e42c3a8dbc5dd9592c606176c7eb5c1ca5ff274bcf907039b2c41de3626f684ea75ccf4d361ba004bbaff1f577d5384c155f3871e456bdf27becf9e
+"combined-stream@npm:^1.0.8":
+ version: 1.0.8
+ resolution: "combined-stream@npm:1.0.8"
+ dependencies:
+ delayed-stream: ~1.0.0
+ checksum: 49fa4aeb4916567e33ea81d088f6584749fc90c7abec76fd516bf1c5aa5c79f3584b5ba3de6b86d26ddd64bae5329c4c7479343250cfe71c75bb366eae53bb7c
languageName: node
linkType: hard
@@ -1169,24 +1142,6 @@ __metadata:
languageName: node
linkType: hard
-"core-util-is@npm:~1.0.0":
- version: 1.0.3
- resolution: "core-util-is@npm:1.0.3"
- checksum: 9de8597363a8e9b9952491ebe18167e3b36e7707569eed0ebf14f8bba773611376466ae34575bca8cfe3c767890c859c74056084738f09d4e4a6f902b2ad7d99
- languageName: node
- linkType: hard
-
-"cross-spawn@npm:^5.0.1":
- version: 5.1.0
- resolution: "cross-spawn@npm:5.1.0"
- dependencies:
- lru-cache: ^4.0.1
- shebang-command: ^1.2.0
- which: ^1.2.9
- checksum: 726939c9954fc70c20e538923feaaa33bebc253247d13021737c3c7f68cdc3e0a57f720c0fe75057c0387995349f3f12e20e9bfdbf12274db28019c7ea4ec166
- languageName: node
- linkType: hard
-
"cross-spawn@npm:^7.0.2":
version: 7.0.3
resolution: "cross-spawn@npm:7.0.3"
@@ -1211,72 +1166,9 @@ __metadata:
linkType: hard
"decimal.js@npm:^10.4.0":
- version: 10.4.0
- resolution: "decimal.js@npm:10.4.0"
- checksum: 98702d9d817a9e5b3767ea6580e7f3b35544b9454e463a5dd5d3232131470f39067d02864c45cab009eb1200bc162cd26a33d34c622cd79e4657a3e25e95fb4e
- languageName: node
- linkType: hard
-
-"decompress-tar@npm:^4.0.0, decompress-tar@npm:^4.1.0, decompress-tar@npm:^4.1.1":
- version: 4.1.1
- resolution: "decompress-tar@npm:4.1.1"
- dependencies:
- file-type: ^5.2.0
- is-stream: ^1.1.0
- tar-stream: ^1.5.2
- checksum: 42d5360b558a28dd884e1bf809e3fea92b9910fda5151add004d4a64cc76ac124e8b3e9117e805f2349af9e49c331d873e6fc5ad86a00e575703fee632b0a225
- languageName: node
- linkType: hard
-
-"decompress-tarbz2@npm:^4.0.0":
- version: 4.1.1
- resolution: "decompress-tarbz2@npm:4.1.1"
- dependencies:
- decompress-tar: ^4.1.0
- file-type: ^6.1.0
- is-stream: ^1.1.0
- seek-bzip: ^1.0.5
- unbzip2-stream: ^1.0.9
- checksum: 519c81337730159a1f2d7072a6ee8523ffd76df48d34f14c27cb0a27f89b4e2acf75dad2f761838e5bc63230cea1ac154b092ecb7504be4e93f7d0e32ddd6aff
- languageName: node
- linkType: hard
-
-"decompress-targz@npm:^4.0.0":
- version: 4.1.1
- resolution: "decompress-targz@npm:4.1.1"
- dependencies:
- decompress-tar: ^4.1.1
- file-type: ^5.2.0
- is-stream: ^1.1.0
- checksum: 22738f58eb034568dc50d370c03b346c428bfe8292fe56165847376b5af17d3c028fefca82db642d79cb094df4c0a599d40a8f294b02aad1d3ddec82f3fd45d4
- languageName: node
- linkType: hard
-
-"decompress-unzip@npm:^4.0.1":
- version: 4.0.1
- resolution: "decompress-unzip@npm:4.0.1"
- dependencies:
- file-type: ^3.8.0
- get-stream: ^2.2.0
- pify: ^2.3.0
- yauzl: ^2.4.2
- checksum: ba9f3204ab2415bedb18d796244928a18148ef40dbb15174d0d01e5991b39536b03d02800a8a389515a1523f8fb13efc7cd44697df758cd06c674879caefd62b
- languageName: node
- linkType: hard
-
-"decompress@npm:^4.1.0":
- version: 4.2.1
- resolution: "decompress@npm:4.2.1"
- dependencies:
- decompress-tar: ^4.0.0
- decompress-tarbz2: ^4.0.0
- decompress-targz: ^4.0.0
- decompress-unzip: ^4.0.1
- graceful-fs: ^4.1.10
- make-dir: ^1.0.0
- pify: ^2.3.0
- strip-dirs: ^2.0.0
- checksum: 8247a31c6db7178413715fdfb35a482f019c81dfcd6e8e623d9f0382c9889ce797ce0144de016b256ed03298907a620ce81387cca0e69067a933470081436cb8
+ version: 10.4.1
+ resolution: "decimal.js@npm:10.4.1"
+ checksum: 5da6dc74af5b73d954741b24d404ef6da07841794d9e51412a2708ec384dd7b4bced3365fb178f4cd119b7ef45f0b34344014a4dc0494c8374c5e746df3cb410
languageName: node
linkType: hard
@@ -1296,10 +1188,10 @@ __metadata:
languageName: node
linkType: hard
-"deep-lock@npm:^1.0.0":
+"delayed-stream@npm:~1.0.0":
version: 1.0.0
- resolution: "deep-lock@npm:1.0.0"
- checksum: e099a64c8c65c142285cea08b122385ba3a88ee37d246ef50e67028ef8da8f4d5b6a42b6129a9d043d2c65ba217b58e955053b16af3d8243c8adcb3721113a0b
+ resolution: "delayed-stream@npm:1.0.0"
+ checksum: 46fe6e83e2cb1d85ba50bd52803c68be9bd953282fa7096f51fc29edd5d67ff84ff753c51966061e5ba7cb5e47ef6d36a91924eddb7f3f3483b1c560f77a0020
languageName: node
linkType: hard
@@ -1326,52 +1218,29 @@ __metadata:
languageName: node
linkType: hard
-"discord-akairo@npm:@notenoughupdates/discord-akairo@dev":
- version: 10.0.0-dev.1661396495.d2761d1
- resolution: "@notenoughupdates/discord-akairo@npm:10.0.0-dev.1661396495.d2761d1"
- dependencies:
- zod: ^3.17.10
- checksum: 69e3dd4d5d0e548f6f1c8075251fe3d386e69f1ef5089e80893057e314bf4d3513855baaa4e17e94d6f862973b19cef171f873b17cdee02ff45dd7a699d7685d
+"discord-api-types@npm:0.37.10, discord-api-types@npm:^0.37.10, discord-api-types@npm:^0.37.3":
+ version: 0.37.10
+ resolution: "discord-api-types@npm:0.37.10"
+ checksum: a09460953a02adf3c40a486e3946c6ca0dd6c76d279444a4595abecfe8b5b88ad49d48b5eeb85e2cb95256a0824ee075cb7550d371c13e64e37ec703206c092b
languageName: node
linkType: hard
-"discord-api-types@npm:0.37.1":
- version: 0.37.1
- resolution: "discord-api-types@npm:0.37.1"
- checksum: 4adfd605dae426299b537105f657b4649535f446202051aaef0ccbbaf024175bdbe868487119480ff094c8e479c2e424ce393f2595b16e1840cc0f3a555e510f
- languageName: node
- linkType: hard
-
-"discord-api-types@npm:^0.36.3":
- version: 0.36.3
- resolution: "discord-api-types@npm:0.36.3"
- checksum: 3089c0fb37425dc5df03c76d82988d43fcc272699b06a02fc830d0a3bef550009aaebdf6d646529e8a7ccea76ae3f43b099d736ea5ef37a0be143142ab49871d
- languageName: node
- linkType: hard
-
-"discord-api-types@npm:^0.37.3":
- version: 0.37.5
- resolution: "discord-api-types@npm:0.37.5"
- checksum: 10a23b813d9a30d836aa27169f768883eeed971ab67e58325ff272bfe6b63b169d727ae983d7c1b69c7e0b02ed9072e66e79319ce48174b36cd4a2a5fafe2e9f
- languageName: node
- linkType: hard
-
-"discord.js@npm:@notenoughupdates/discord.js@forum":
- version: 14.1.2-forum
- resolution: "@notenoughupdates/discord.js@npm:14.1.2-forum"
+"discord.js@npm:@notenoughupdates/discord.js@dev":
+ version: 14.5.1-dev.1664157090-edb72ba.0
+ resolution: "@notenoughupdates/discord.js@npm:14.5.1-dev.1664157090-edb72ba.0"
dependencies:
- "@discordjs/builders": "workspace:^"
- "@discordjs/collection": "workspace:^"
- "@discordjs/rest": "workspace:^"
+ "@discordjs/builders": ^1.2.0
+ "@discordjs/collection": ^1.1.0
+ "@discordjs/rest": ^1.2.0
"@sapphire/snowflake": ^3.2.2
"@types/ws": ^8.5.3
- discord-api-types: ^0.36.3
+ discord-api-types: ^0.37.10
fast-deep-equal: ^3.1.3
lodash.snakecase: ^4.1.1
tslib: ^2.4.0
- undici: ^5.8.0
- ws: ^8.8.1
- checksum: abcc01e4b72d89875db497cf8bd75d2f0b5b09946671f8ffad5f2c9e7cfbec82912bfe354e561a6b709fcf6a7261bf79d622122487c04acd76d681a74bda1d3f
+ undici: ^5.10.0
+ ws: ^8.9.0
+ checksum: a5fb3a8b269ad9c279e3839a1dda4d6ce9e54e6eef4cc9a4a08996cddb49c045faa347e3696d1ed58432e7707b886298ada1b2c4ed2522edbd9d0bfc71d53abc
languageName: node
linkType: hard
@@ -1416,15 +1285,6 @@ __metadata:
languageName: node
linkType: hard
-"end-of-stream@npm:^1.0.0":
- version: 1.4.4
- resolution: "end-of-stream@npm:1.4.4"
- dependencies:
- once: ^1.4.0
- checksum: 530a5a5a1e517e962854a31693dbb5c0b2fc40b46dad2a56a2deec656ca040631124f4795823acc68238147805f8b021abbe221f4afed5ef3c8e8efc2024908b
- languageName: node
- linkType: hard
-
"env-paths@npm:^2.2.0":
version: 2.2.1
resolution: "env-paths@npm:2.2.1"
@@ -1439,172 +1299,175 @@ __metadata:
languageName: node
linkType: hard
-"esbuild-android-64@npm:0.14.54":
- version: 0.14.54
- resolution: "esbuild-android-64@npm:0.14.54"
+"esbuild-android-64@npm:0.15.9":
+ version: 0.15.9
+ resolution: "esbuild-android-64@npm:0.15.9"
conditions: os=android & cpu=x64
languageName: node
linkType: hard
-"esbuild-android-arm64@npm:0.14.54":
- version: 0.14.54
- resolution: "esbuild-android-arm64@npm:0.14.54"
+"esbuild-android-arm64@npm:0.15.9":
+ version: 0.15.9
+ resolution: "esbuild-android-arm64@npm:0.15.9"
conditions: os=android & cpu=arm64
languageName: node
linkType: hard
-"esbuild-darwin-64@npm:0.14.54":
- version: 0.14.54
- resolution: "esbuild-darwin-64@npm:0.14.54"
+"esbuild-darwin-64@npm:0.15.9":
+ version: 0.15.9
+ resolution: "esbuild-darwin-64@npm:0.15.9"
conditions: os=darwin & cpu=x64
languageName: node
linkType: hard
-"esbuild-darwin-arm64@npm:0.14.54":
- version: 0.14.54
- resolution: "esbuild-darwin-arm64@npm:0.14.54"
+"esbuild-darwin-arm64@npm:0.15.9":
+ version: 0.15.9
+ resolution: "esbuild-darwin-arm64@npm:0.15.9"
conditions: os=darwin & cpu=arm64
languageName: node
linkType: hard
-"esbuild-freebsd-64@npm:0.14.54":
- version: 0.14.54
- resolution: "esbuild-freebsd-64@npm:0.14.54"
+"esbuild-freebsd-64@npm:0.15.9":
+ version: 0.15.9
+ resolution: "esbuild-freebsd-64@npm:0.15.9"
conditions: os=freebsd & cpu=x64
languageName: node
linkType: hard
-"esbuild-freebsd-arm64@npm:0.14.54":
- version: 0.14.54
- resolution: "esbuild-freebsd-arm64@npm:0.14.54"
+"esbuild-freebsd-arm64@npm:0.15.9":
+ version: 0.15.9
+ resolution: "esbuild-freebsd-arm64@npm:0.15.9"
conditions: os=freebsd & cpu=arm64
languageName: node
linkType: hard
-"esbuild-linux-32@npm:0.14.54":
- version: 0.14.54
- resolution: "esbuild-linux-32@npm:0.14.54"
+"esbuild-linux-32@npm:0.15.9":
+ version: 0.15.9
+ resolution: "esbuild-linux-32@npm:0.15.9"
conditions: os=linux & cpu=ia32
languageName: node
linkType: hard
-"esbuild-linux-64@npm:0.14.54":
- version: 0.14.54
- resolution: "esbuild-linux-64@npm:0.14.54"
+"esbuild-linux-64@npm:0.15.9":
+ version: 0.15.9
+ resolution: "esbuild-linux-64@npm:0.15.9"
conditions: os=linux & cpu=x64
languageName: node
linkType: hard
-"esbuild-linux-arm64@npm:0.14.54":
- version: 0.14.54
- resolution: "esbuild-linux-arm64@npm:0.14.54"
+"esbuild-linux-arm64@npm:0.15.9":
+ version: 0.15.9
+ resolution: "esbuild-linux-arm64@npm:0.15.9"
conditions: os=linux & cpu=arm64
languageName: node
linkType: hard
-"esbuild-linux-arm@npm:0.14.54":
- version: 0.14.54
- resolution: "esbuild-linux-arm@npm:0.14.54"
+"esbuild-linux-arm@npm:0.15.9":
+ version: 0.15.9
+ resolution: "esbuild-linux-arm@npm:0.15.9"
conditions: os=linux & cpu=arm
languageName: node
linkType: hard
-"esbuild-linux-mips64le@npm:0.14.54":
- version: 0.14.54
- resolution: "esbuild-linux-mips64le@npm:0.14.54"
+"esbuild-linux-mips64le@npm:0.15.9":
+ version: 0.15.9
+ resolution: "esbuild-linux-mips64le@npm:0.15.9"
conditions: os=linux & cpu=mips64el
languageName: node
linkType: hard
-"esbuild-linux-ppc64le@npm:0.14.54":
- version: 0.14.54
- resolution: "esbuild-linux-ppc64le@npm:0.14.54"
+"esbuild-linux-ppc64le@npm:0.15.9":
+ version: 0.15.9
+ resolution: "esbuild-linux-ppc64le@npm:0.15.9"
conditions: os=linux & cpu=ppc64
languageName: node
linkType: hard
-"esbuild-linux-riscv64@npm:0.14.54":
- version: 0.14.54
- resolution: "esbuild-linux-riscv64@npm:0.14.54"
+"esbuild-linux-riscv64@npm:0.15.9":
+ version: 0.15.9
+ resolution: "esbuild-linux-riscv64@npm:0.15.9"
conditions: os=linux & cpu=riscv64
languageName: node
linkType: hard
-"esbuild-linux-s390x@npm:0.14.54":
- version: 0.14.54
- resolution: "esbuild-linux-s390x@npm:0.14.54"
+"esbuild-linux-s390x@npm:0.15.9":
+ version: 0.15.9
+ resolution: "esbuild-linux-s390x@npm:0.15.9"
conditions: os=linux & cpu=s390x
languageName: node
linkType: hard
-"esbuild-netbsd-64@npm:0.14.54":
- version: 0.14.54
- resolution: "esbuild-netbsd-64@npm:0.14.54"
+"esbuild-netbsd-64@npm:0.15.9":
+ version: 0.15.9
+ resolution: "esbuild-netbsd-64@npm:0.15.9"
conditions: os=netbsd & cpu=x64
languageName: node
linkType: hard
-"esbuild-openbsd-64@npm:0.14.54":
- version: 0.14.54
- resolution: "esbuild-openbsd-64@npm:0.14.54"
+"esbuild-openbsd-64@npm:0.15.9":
+ version: 0.15.9
+ resolution: "esbuild-openbsd-64@npm:0.15.9"
conditions: os=openbsd & cpu=x64
languageName: node
linkType: hard
-"esbuild-sunos-64@npm:0.14.54":
- version: 0.14.54
- resolution: "esbuild-sunos-64@npm:0.14.54"
+"esbuild-sunos-64@npm:0.15.9":
+ version: 0.15.9
+ resolution: "esbuild-sunos-64@npm:0.15.9"
conditions: os=sunos & cpu=x64
languageName: node
linkType: hard
-"esbuild-windows-32@npm:0.14.54":
- version: 0.14.54
- resolution: "esbuild-windows-32@npm:0.14.54"
+"esbuild-windows-32@npm:0.15.9":
+ version: 0.15.9
+ resolution: "esbuild-windows-32@npm:0.15.9"
conditions: os=win32 & cpu=ia32
languageName: node
linkType: hard
-"esbuild-windows-64@npm:0.14.54":
- version: 0.14.54
- resolution: "esbuild-windows-64@npm:0.14.54"
+"esbuild-windows-64@npm:0.15.9":
+ version: 0.15.9
+ resolution: "esbuild-windows-64@npm:0.15.9"
conditions: os=win32 & cpu=x64
languageName: node
linkType: hard
-"esbuild-windows-arm64@npm:0.14.54":
- version: 0.14.54
- resolution: "esbuild-windows-arm64@npm:0.14.54"
+"esbuild-windows-arm64@npm:0.15.9":
+ version: 0.15.9
+ resolution: "esbuild-windows-arm64@npm:0.15.9"
conditions: os=win32 & cpu=arm64
languageName: node
linkType: hard
-"esbuild@npm:^0.14.47":
- version: 0.14.54
- resolution: "esbuild@npm:0.14.54"
- dependencies:
- "@esbuild/linux-loong64": 0.14.54
- esbuild-android-64: 0.14.54
- esbuild-android-arm64: 0.14.54
- esbuild-darwin-64: 0.14.54
- esbuild-darwin-arm64: 0.14.54
- esbuild-freebsd-64: 0.14.54
- esbuild-freebsd-arm64: 0.14.54
- esbuild-linux-32: 0.14.54
- esbuild-linux-64: 0.14.54
- esbuild-linux-arm: 0.14.54
- esbuild-linux-arm64: 0.14.54
- esbuild-linux-mips64le: 0.14.54
- esbuild-linux-ppc64le: 0.14.54
- esbuild-linux-riscv64: 0.14.54
- esbuild-linux-s390x: 0.14.54
- esbuild-netbsd-64: 0.14.54
- esbuild-openbsd-64: 0.14.54
- esbuild-sunos-64: 0.14.54
- esbuild-windows-32: 0.14.54
- esbuild-windows-64: 0.14.54
- esbuild-windows-arm64: 0.14.54
+"esbuild@npm:^0.15.6":
+ version: 0.15.9
+ resolution: "esbuild@npm:0.15.9"
+ dependencies:
+ "@esbuild/android-arm": 0.15.9
+ "@esbuild/linux-loong64": 0.15.9
+ esbuild-android-64: 0.15.9
+ esbuild-android-arm64: 0.15.9
+ esbuild-darwin-64: 0.15.9
+ esbuild-darwin-arm64: 0.15.9
+ esbuild-freebsd-64: 0.15.9
+ esbuild-freebsd-arm64: 0.15.9
+ esbuild-linux-32: 0.15.9
+ esbuild-linux-64: 0.15.9
+ esbuild-linux-arm: 0.15.9
+ esbuild-linux-arm64: 0.15.9
+ esbuild-linux-mips64le: 0.15.9
+ esbuild-linux-ppc64le: 0.15.9
+ esbuild-linux-riscv64: 0.15.9
+ esbuild-linux-s390x: 0.15.9
+ esbuild-netbsd-64: 0.15.9
+ esbuild-openbsd-64: 0.15.9
+ esbuild-sunos-64: 0.15.9
+ esbuild-windows-32: 0.15.9
+ esbuild-windows-64: 0.15.9
+ esbuild-windows-arm64: 0.15.9
dependenciesMeta:
+ "@esbuild/android-arm":
+ optional: true
"@esbuild/linux-loong64":
optional: true
esbuild-android-64:
@@ -1649,7 +1512,7 @@ __metadata:
optional: true
bin:
esbuild: bin/esbuild
- checksum: 49e360b1185c797f5ca3a7f5f0a75121494d97ddf691f65ed1796e6257d318f928342a97f559bb8eced6a90cf604dd22db4a30e0dbbf15edd9dbf22459b639af
+ checksum: 33da8cc0c7bd03f1acfafd51812638fd75ae01f95db3737dbc4d94a9f9e9c234df2ffc76c0fa7147f2466c342b7085f835edc93b3a3dac84aaa1cf46ed80b980
languageName: node
linkType: hard
@@ -1737,12 +1600,12 @@ __metadata:
languageName: node
linkType: hard
-"eslint@npm:^8.23.0":
- version: 8.23.0
- resolution: "eslint@npm:8.23.0"
+"eslint@npm:^8.24.0":
+ version: 8.24.0
+ resolution: "eslint@npm:8.24.0"
dependencies:
- "@eslint/eslintrc": ^1.3.1
- "@humanwhocodes/config-array": ^0.10.4
+ "@eslint/eslintrc": ^1.3.2
+ "@humanwhocodes/config-array": ^0.10.5
"@humanwhocodes/gitignore-to-minimatch": ^1.0.2
"@humanwhocodes/module-importer": ^1.0.1
ajv: ^6.10.0
@@ -1760,7 +1623,6 @@ __metadata:
fast-deep-equal: ^3.1.3
file-entry-cache: ^6.0.1
find-up: ^5.0.0
- functional-red-black-tree: ^1.0.1
glob-parent: ^6.0.1
globals: ^13.15.0
globby: ^11.1.0
@@ -1769,6 +1631,7 @@ __metadata:
import-fresh: ^3.0.0
imurmurhash: ^0.1.4
is-glob: ^4.0.0
+ js-sdsl: ^4.1.4
js-yaml: ^4.1.0
json-stable-stringify-without-jsonify: ^1.0.1
levn: ^0.4.1
@@ -1782,7 +1645,7 @@ __metadata:
text-table: ^0.2.0
bin:
eslint: bin/eslint.js
- checksum: ff6075daa28d817a7ac4508f31bc108a04d9ab5056608c8651b5bf9cfea5d708ca16dea6cdab2c3c0ae99b0bf0e726af8504eaa8e17c8e12e242cb68237ead64
+ checksum: ca293ce7116599b742d7ab4d43db469beec22f40dd272092d809498be3cff3a7c567769f9763bdf6799aac13dd53447b93a99629b7b54092783046eb57eaced6
languageName: node
linkType: hard
@@ -1836,21 +1699,6 @@ __metadata:
languageName: node
linkType: hard
-"execa@npm:^0.6.3":
- version: 0.6.3
- resolution: "execa@npm:0.6.3"
- dependencies:
- cross-spawn: ^5.0.1
- get-stream: ^3.0.0
- is-stream: ^1.1.0
- npm-run-path: ^2.0.0
- p-finally: ^1.0.0
- signal-exit: ^3.0.0
- strip-eof: ^1.0.0
- checksum: 2c66177731273a7c0a4c031af81b486b67ec1eeeb8f353ebc68e0cfe7f63aca9ebc1e6fe03ba10f130f2bd179c0ac69b35668fe2bfc1ceb68fbf5291d0783457
- languageName: node
- linkType: hard
-
"extend@npm:^3.0.2":
version: 3.0.2
resolution: "extend@npm:3.0.2"
@@ -1866,15 +1714,15 @@ __metadata:
linkType: hard
"fast-glob@npm:^3.2.9":
- version: 3.2.11
- resolution: "fast-glob@npm:3.2.11"
+ version: 3.2.12
+ resolution: "fast-glob@npm:3.2.12"
dependencies:
"@nodelib/fs.stat": ^2.0.2
"@nodelib/fs.walk": ^1.2.3
glob-parent: ^5.1.2
merge2: ^1.3.0
micromatch: ^4.0.4
- checksum: f473105324a7780a20c06de842e15ddbb41d3cb7e71d1e4fe6e8373204f22245d54f5ab9e2061e6a1c613047345954d29b022e0e76f5c28b1df9858179a0e6d7
+ checksum: 0b1990f6ce831c7e28c4d505edcdaad8e27e88ab9fa65eedadb730438cfc7cde4910d6c975d6b7b8dc8a73da4773702ebcfcd6e3518e73938bb1383badfe01c2
languageName: node
linkType: hard
@@ -1893,9 +1741,9 @@ __metadata:
linkType: hard
"fast-text-encoding@npm:^1.0.0":
- version: 1.0.4
- resolution: "fast-text-encoding@npm:1.0.4"
- checksum: aa92d27451ad972ac8391b40f8680dc6722513b0b9c123bc6991fb789e46302a89d76a4e23a3071ca2071a63e5e116a0c75d790703a5568b22019350196e405d
+ version: 1.0.6
+ resolution: "fast-text-encoding@npm:1.0.6"
+ checksum: 9d58f694314b3283e785bf61954902536da228607ad246905e30256f9ab8331f780ac987e7222c9f5eafd04168d07e12b8054c85cedb76a2c05af0e82387a903
languageName: node
linkType: hard
@@ -1908,15 +1756,6 @@ __metadata:
languageName: node
linkType: hard
-"fd-slicer@npm:~1.1.0":
- version: 1.1.0
- resolution: "fd-slicer@npm:1.1.0"
- dependencies:
- pend: ~1.2.0
- checksum: c8585fd5713f4476eb8261150900d2cb7f6ff2d87f8feb306ccc8a1122efd152f1783bdb2b8dc891395744583436bfd8081d8e63ece0ec8687eeefea394d4ff2
- languageName: node
- linkType: hard
-
"file-entry-cache@npm:^6.0.1":
version: 6.0.1
resolution: "file-entry-cache@npm:6.0.1"
@@ -1926,35 +1765,14 @@ __metadata:
languageName: node
linkType: hard
-"file-type@npm:^17.1.6":
- version: 17.1.6
- resolution: "file-type@npm:17.1.6"
+"file-type@npm:^18.0.0":
+ version: 18.0.0
+ resolution: "file-type@npm:18.0.0"
dependencies:
readable-web-to-node-stream: ^3.0.2
- strtok3: ^7.0.0-alpha.9
- token-types: ^5.0.0-alpha.2
- checksum: 797e0d155ecaf4b575d4569a0188bfed85af19d18cf3d93ec8bb66d797172a1fde9f13d56135c6a0b471cacd7ecc1adb0c9a45c6e3a19436f682a275d0be16cc
- languageName: node
- linkType: hard
-
-"file-type@npm:^3.8.0":
- version: 3.9.0
- resolution: "file-type@npm:3.9.0"
- checksum: 1db70b2485ac77c4edb4b8753c1874ee6194123533f43c2651820f96b518f505fa570b093fedd6672eb105ba9fb89c62f84b6492e46788e39c3447aed37afa2d
- languageName: node
- linkType: hard
-
-"file-type@npm:^5.2.0":
- version: 5.2.0
- resolution: "file-type@npm:5.2.0"
- checksum: b2b21c7fc3cfb3c6a3a18b0d5d7233b74d8c17d82757655766573951daf42962a5c809e5fc3637675b237c558ebc67e4958fb2cc5a4ad407bc545aaa40001c74
- languageName: node
- linkType: hard
-
-"file-type@npm:^6.1.0":
- version: 6.2.0
- resolution: "file-type@npm:6.2.0"
- checksum: 749540cefcd4959121eb83e373ed84e49b2e5a510aa5d598b725bd772dd306ae41fd00d3162ae3f6563b4db5cfafbbd0df321de3f20c17e20a8c56431ae55e58
+ strtok3: ^7.0.0
+ token-types: ^5.0.1
+ checksum: 67f5a927b8030e35a4faf9dd9dea9e17bcb042fb61b9851b7dd1b1b3bb3ecfdd9f83bc3bc72686316ea2bac70df652c61e10affa9b5957b1a3d731df4925e3cb
languageName: node
linkType: hard
@@ -1994,6 +1812,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
+
"fraction.js@npm:^4.2.0":
version: 4.2.0
resolution: "fraction.js@npm:4.2.0"
@@ -2001,13 +1830,6 @@ __metadata:
languageName: node
linkType: hard
-"fs-constants@npm:^1.0.0":
- version: 1.0.0
- resolution: "fs-constants@npm:1.0.0"
- checksum: 18f5b718371816155849475ac36c7d0b24d39a11d91348cfcb308b4494824413e03572c403c86d3a260e049465518c4f0d5bd00f0371cdfcad6d4f30a85b350d
- languageName: node
- linkType: hard
-
"fs-minipass@npm:^2.0.0, fs-minipass@npm:^2.1.0":
version: 2.1.0
resolution: "fs-minipass@npm:2.1.0"
@@ -2050,13 +1872,6 @@ __metadata:
languageName: node
linkType: hard
-"functional-red-black-tree@npm:^1.0.1":
- version: 1.0.1
- resolution: "functional-red-black-tree@npm:1.0.1"
- checksum: ca6c170f37640e2d94297da8bb4bf27a1d12bea3e00e6a3e007fd7aa32e37e000f5772acf941b4e4f3cf1c95c3752033d0c509af157ad8f526e7f00723b9eb9f
- languageName: node
- linkType: hard
-
"fuse.js@npm:^6.6.2":
version: 6.6.2
resolution: "fuse.js@npm:6.6.2"
@@ -2110,40 +1925,13 @@ __metadata:
linkType: hard
"get-intrinsic@npm:^1.0.2":
- version: 1.1.2
- resolution: "get-intrinsic@npm:1.1.2"
+ version: 1.1.3
+ resolution: "get-intrinsic@npm:1.1.3"
dependencies:
function-bind: ^1.1.1
has: ^1.0.3
has-symbols: ^1.0.3
- checksum: 252f45491f2ba88ebf5b38018020c7cc3279de54b1d67ffb70c0cdf1dfa8ab31cd56467b5d117a8b4275b7a4dde91f86766b163a17a850f036528a7b2faafb2b
- languageName: node
- linkType: hard
-
-"get-stream@npm:^2.2.0":
- version: 2.3.1
- resolution: "get-stream@npm:2.3.1"
- dependencies:
- object-assign: ^4.0.1
- pinkie-promise: ^2.0.0
- checksum: d82c86556e131ba7bef00233aa0aa7a51230e6deac11a971ce0f47cd43e2a5e968a3e3914cd082f07cd0d69425653b2f96735b0a7d5c5c03fef3ab857a531367
- languageName: node
- linkType: hard
-
-"get-stream@npm:^3.0.0":
- version: 3.0.0
- resolution: "get-stream@npm:3.0.0"
- checksum: 36142f46005ed74ce3a45c55545ec4e7da8e243554179e345a786baf144e5c4a35fb7bdc49fadfa9f18bd08000589b6fe364abdadfc4e1eb0e1b9914a6bb9c56
- languageName: node
- linkType: hard
-
-"gif-to-apng@npm:^0.1.2":
- version: 0.1.2
- resolution: "gif-to-apng@npm:0.1.2"
- dependencies:
- decompress: ^4.1.0
- execa: ^0.6.3
- checksum: 2f545858151960d9eb8b18d2b6c6f882280a9e99aba8c11a036444461013fe32a1291946207d1a6b31a74cec3cfcca3780d1e3d398cf0a6f2d203c12642e42ac
+ checksum: 152d79e87251d536cf880ba75cfc3d6c6c50e12b3a64e1ea960e73a3752b47c69f46034456eae1b0894359ce3bc64c55c186f2811f8a788b75b638b06fab228a
languageName: node
linkType: hard
@@ -2216,8 +2004,8 @@ __metadata:
linkType: hard
"google-auth-library@npm:^8.0.2":
- version: 8.4.0
- resolution: "google-auth-library@npm:8.4.0"
+ version: 8.5.2
+ resolution: "google-auth-library@npm:8.5.2"
dependencies:
arrify: ^2.0.0
base64-js: ^1.3.0
@@ -2228,7 +2016,7 @@ __metadata:
gtoken: ^6.1.0
jws: ^4.0.0
lru-cache: ^6.0.0
- checksum: 4f3f52399c851dff3be797f888e675dbb6099613fcd934aece0d1527b9e9a77e5aadc9be12d137981d2d820a59050b0baf29ea126d2722e20a3e1adf425c93e6
+ checksum: 5ab2904f5da3c119a7c241a1d5a11640468a7da58dfcec8a9cad181cc2723e6662b3c65997906069852d9fa066ba3e4b7f14e11cbb80d541e320b66ead6777dc
languageName: node
linkType: hard
@@ -2244,30 +2032,30 @@ __metadata:
linkType: hard
"googleapis-common@npm:^6.0.0":
- version: 6.0.1
- resolution: "googleapis-common@npm:6.0.1"
+ version: 6.0.3
+ resolution: "googleapis-common@npm:6.0.3"
dependencies:
extend: ^3.0.2
gaxios: ^5.0.1
google-auth-library: ^8.0.2
qs: ^6.7.0
url-template: ^2.0.8
- uuid: ^8.0.0
- checksum: 46bfdd4673006075e3349500e312f2267f1d2830434d76b7b20d8de3ebfb9c5a3f525cc88b6e89f5d8f5f8f3ff9fcee90e4667dac45306cddb05d0f70b97b999
+ uuid: ^9.0.0
+ checksum: 72b3f2f4018d96d6e5bcc08096c693e393ba1ae59be243ac409e8876d941f918aad556a62d828709956552a5940295360674b9681b7871a1b3be54ea8a588f3f
languageName: node
linkType: hard
-"googleapis@npm:^107.0.0":
- version: 107.0.0
- resolution: "googleapis@npm:107.0.0"
+"googleapis@npm:^108.0.0":
+ version: 108.0.0
+ resolution: "googleapis@npm:108.0.0"
dependencies:
google-auth-library: ^8.0.2
googleapis-common: ^6.0.0
- checksum: 6cf90ad0039d61d65aacdfca9eb98af55ae380ec1b4cea43b58b49d765b924e8b5307e4c4e3b0f0128f53cab813fbdeaaf36522b60bb0a114c218c62a95f8f97
+ checksum: 30f22202d174bcf7b2f02645785341953aaaa6280a40991ff6b77fae293945354a92e78f59e565529aee65c85e70e57147f8d991c7ae1f4593a5a9588613cc90
languageName: node
linkType: hard
-"graceful-fs@npm:^4.1.10, graceful-fs@npm:^4.2.6":
+"graceful-fs@npm:^4.2.6":
version: 4.2.10
resolution: "graceful-fs@npm:4.2.10"
checksum: 3f109d70ae123951905d85032ebeae3c2a5a7a997430df00ea30df0e3a6c60cf6689b109654d6fdacd28810a053348c4d14642da1d075049e6be1ba5216218da
@@ -2282,13 +2070,13 @@ __metadata:
linkType: hard
"gtoken@npm:^6.1.0":
- version: 6.1.1
- resolution: "gtoken@npm:6.1.1"
+ version: 6.1.2
+ resolution: "gtoken@npm:6.1.2"
dependencies:
gaxios: ^5.0.1
google-p12-pem: ^4.0.0
jws: ^4.0.0
- checksum: f063ed3f418f5a9c33fbe599b09f56a55b18f6c8d2913f11cc2fc5025d53b96fd6ab1b4deb2c7631167d6b89d0939e4ea77f94767fcf338862ffda8911250980
+ checksum: cf3210afe2ccee8feaa06f0c7eb942e217244a8563a1d0a71aa3095eea545015896741c1d48654d8de35b7b07579f93e25e5dfe817f06b7e753646b67f7a4ecf
languageName: node
linkType: hard
@@ -2368,7 +2156,7 @@ __metadata:
languageName: node
linkType: hard
-"ieee754@npm:^1.1.13, ieee754@npm:^1.2.1":
+"ieee754@npm:^1.2.1":
version: 1.2.1
resolution: "ieee754@npm:1.2.1"
checksum: 5144c0c9815e54ada181d80a0b810221a253562422e7c6c3a60b1901154184f49326ec239d618c416c1c5945a2e197107aee8d986a3dd836b53dffefd99b5e7e
@@ -2421,9 +2209,9 @@ __metadata:
linkType: hard
"inflection@npm:^1.13.2":
- version: 1.13.2
- resolution: "inflection@npm:1.13.2"
- checksum: e7ad0559384ed7c526813404bde843f8f17941d47625ad60fc3b09e46efde873dd9840818007c6bd4dbe388e6248fa033d5a8c405c5fc62738c51b118a0e940f
+ version: 1.13.4
+ resolution: "inflection@npm:1.13.4"
+ checksum: 6744feede9998ad8abd2b1db4af79f494a166e656a0aa949d90c8f4a945c1d07038a3756bf7af78c8f6fce368ba213a7ebf35da3edeffd39f1da0ff465eed6eb
languageName: node
linkType: hard
@@ -2437,7 +2225,7 @@ __metadata:
languageName: node
linkType: hard
-"inherits@npm:2, inherits@npm:^2.0.3, inherits@npm:~2.0.3":
+"inherits@npm:2, inherits@npm:^2.0.3":
version: 2.0.4
resolution: "inherits@npm:2.0.4"
checksum: 4a48a733847879d6cf6691860a6b1e3f0f4754176e4d71494c41f3475553768b10f84b5ce1d40fbd0e34e6bfbb864ee35858ad4dd2cf31e02fc4a154b724d7f1
@@ -2490,13 +2278,6 @@ __metadata:
languageName: node
linkType: hard
-"is-natural-number@npm:^4.0.1":
- version: 4.0.1
- resolution: "is-natural-number@npm:4.0.1"
- checksum: 3e5e3d52e0dfa4fea923b5d2b8a5cdbd9bf110c4598d30304b98528b02f40c9058a2abf1bae10bcbaf2bac18ace41cff7bc9673aff339f8c8297fae74ae0e75d
- languageName: node
- linkType: hard
-
"is-number@npm:^7.0.0":
version: 7.0.0
resolution: "is-number@npm:7.0.0"
@@ -2504,13 +2285,6 @@ __metadata:
languageName: node
linkType: hard
-"is-stream@npm:^1.1.0":
- version: 1.1.0
- resolution: "is-stream@npm:1.1.0"
- checksum: 063c6bec9d5647aa6d42108d4c59723d2bd4ae42135a2d4db6eadbd49b7ea05b750fd69d279e5c7c45cf9da753ad2c00d8978be354d65aa9f6bb434969c6a2ae
- languageName: node
- linkType: hard
-
"is-stream@npm:^2.0.0":
version: 2.0.1
resolution: "is-stream@npm:2.0.1"
@@ -2518,13 +2292,6 @@ __metadata:
languageName: node
linkType: hard
-"isarray@npm:~1.0.0":
- version: 1.0.0
- resolution: "isarray@npm:1.0.0"
- checksum: f032df8e02dce8ec565cf2eb605ea939bdccea528dbcf565cdf92bfa2da9110461159d86a537388ef1acef8815a330642d7885b29010e8f7eac967c9993b65ab
- languageName: node
- linkType: hard
-
"isexe@npm:^2.0.0":
version: 2.0.0
resolution: "isexe@npm:2.0.0"
@@ -2539,6 +2306,13 @@ __metadata:
languageName: node
linkType: hard
+"js-sdsl@npm:^4.1.4":
+ version: 4.1.4
+ resolution: "js-sdsl@npm:4.1.4"
+ checksum: 1977cea4ab18e0e03e28bdf0371d8b443fad65ca0988e0faa216406faf6bb943714fe8f7cc7a5bfe5f35ba3d94ddae399f4d10200f547f2c3320688b0670d726
+ languageName: node
+ linkType: hard
+
"js-yaml@npm:^4.1.0":
version: 4.1.0
resolution: "js-yaml@npm:4.1.0"
@@ -2638,6 +2412,13 @@ __metadata:
languageName: node
linkType: hard
+"lodash-es@npm:^4.17.21":
+ version: 4.17.21
+ resolution: "lodash-es@npm:4.17.21"
+ checksum: 05cbffad6e2adbb331a4e16fbd826e7faee403a1a04873b82b42c0f22090f280839f85b95393f487c1303c8a3d2a010048bf06151a6cbe03eee4d388fb0a12d2
+ languageName: node
+ linkType: hard
+
"lodash.merge@npm:^4.6.2":
version: 4.6.2
resolution: "lodash.merge@npm:4.6.2"
@@ -2675,16 +2456,6 @@ __metadata:
languageName: node
linkType: hard
-"lru-cache@npm:^4.0.1":
- version: 4.1.5
- resolution: "lru-cache@npm:4.1.5"
- dependencies:
- pseudomap: ^1.0.2
- yallist: ^2.1.2
- checksum: 4bb4b58a36cd7dc4dcec74cbe6a8f766a38b7426f1ff59d4cf7d82a2aa9b9565cd1cb98f6ff60ce5cd174524868d7bc9b7b1c294371851356066ca9ac4cf135a
- languageName: node
- linkType: hard
-
"lru-cache@npm:^6.0.0":
version: 6.0.0
resolution: "lru-cache@npm:6.0.0"
@@ -2708,15 +2479,6 @@ __metadata:
languageName: node
linkType: hard
-"make-dir@npm:^1.0.0":
- version: 1.3.0
- resolution: "make-dir@npm:1.3.0"
- dependencies:
- pify: ^3.0.0
- checksum: c564f6e7bb5ace1c02ad56b3a5f5e07d074af0c0b693c55c7b2c2b148882827c8c2afc7b57e43338a9f90c125b58d604e8cf3e6990a48bf949dfea8c79668c0b
- languageName: node
- linkType: hard
-
"make-fetch-happen@npm:^10.0.3":
version: 10.2.1
resolution: "make-fetch-happen@npm:10.2.1"
@@ -2741,11 +2503,11 @@ __metadata:
languageName: node
linkType: hard
-"mathjs@npm:^11.1.0":
- version: 11.1.0
- resolution: "mathjs@npm:11.1.0"
+"mathjs@npm:^11.2.1":
+ version: 11.2.1
+ resolution: "mathjs@npm:11.2.1"
dependencies:
- "@babel/runtime": ^7.18.9
+ "@babel/runtime": ^7.19.0
complex.js: ^2.1.1
decimal.js: ^10.4.0
escape-latex: ^1.2.0
@@ -2756,7 +2518,7 @@ __metadata:
typed-function: ^4.1.0
bin:
mathjs: bin/cli.js
- checksum: 66d1c285e18478d8d5e07b8e67268a58bf296f21c5a72cddfcefc46fe81c5876eee77b4a630f9191a6cbd789d3ac1d5d2380adb4e83fd0569949c9f70ffa48df
+ checksum: 83ff278bc7a633757ca0b81f2c7c60f8ea70fb077266f60ea6b25a09325ba71f27096d08b3eeb58e8c438b9252e5b70e4a770842830cc249aaa85d523ed19616
languageName: node
linkType: hard
@@ -2777,6 +2539,22 @@ __metadata:
languageName: node
linkType: hard
+"mime-db@npm:1.52.0":
+ version: 1.52.0
+ resolution: "mime-db@npm:1.52.0"
+ checksum: 0d99a03585f8b39d68182803b12ac601d9c01abfa28ec56204fa330bc9f3d1c5e14beb049bafadb3dbdf646dfb94b87e24d4ec7b31b7279ef906a8ea9b6a513f
+ languageName: node
+ linkType: hard
+
+"mime-types@npm:^2.1.12":
+ version: 2.1.35
+ resolution: "mime-types@npm:2.1.35"
+ dependencies:
+ mime-db: 1.52.0
+ checksum: 89a5b7f1def9f3af5dad6496c5ed50191ae4331cc5389d7c521c8ad28d5fdad2d06fd81baf38fed813dc4e46bb55c8145bb0ff406330818c9cf712fb2e9b3836
+ languageName: node
+ linkType: hard
+
"minimatch@npm:^3.0.4, minimatch@npm:^3.1.1, minimatch@npm:^3.1.2":
version: 3.1.2
resolution: "minimatch@npm:3.1.2"
@@ -2988,15 +2766,6 @@ __metadata:
languageName: node
linkType: hard
-"npm-run-path@npm:^2.0.0":
- version: 2.0.2
- resolution: "npm-run-path@npm:2.0.2"
- dependencies:
- path-key: ^2.0.0
- checksum: acd5ad81648ba4588ba5a8effb1d98d2b339d31be16826a118d50f182a134ac523172101b82eab1d01cb4c2ba358e857d54cfafd8163a1ffe7bd52100b741125
- languageName: node
- linkType: hard
-
"npmlog@npm:^6.0.0":
version: 6.0.2
resolution: "npmlog@npm:6.0.2"
@@ -3016,13 +2785,6 @@ __metadata:
languageName: node
linkType: hard
-"object-assign@npm:^4.0.1":
- version: 4.1.1
- resolution: "object-assign@npm:4.1.1"
- checksum: fcc6e4ea8c7fe48abfbb552578b1c53e0d194086e2e6bbbf59e0a536381a292f39943c6e9628af05b5528aa5e3318bb30d6b2e53cadaf5b8fe9e12c4b69af23f
- languageName: node
- linkType: hard
-
"object-inspect@npm:^1.9.0":
version: 1.12.2
resolution: "object-inspect@npm:1.12.2"
@@ -3030,7 +2792,7 @@ __metadata:
languageName: node
linkType: hard
-"once@npm:^1.3.0, once@npm:^1.4.0":
+"once@npm:^1.3.0":
version: 1.4.0
resolution: "once@npm:1.4.0"
dependencies:
@@ -3053,13 +2815,6 @@ __metadata:
languageName: node
linkType: hard
-"p-finally@npm:^1.0.0":
- version: 1.0.0
- resolution: "p-finally@npm:1.0.0"
- checksum: 93a654c53dc805dd5b5891bab16eb0ea46db8f66c4bfd99336ae929323b1af2b70a8b0654f8f1eae924b2b73d037031366d645f1fd18b3d30cbd15950cc4b1d4
- languageName: node
- linkType: hard
-
"p-limit@npm:^3.0.2":
version: 3.1.0
resolution: "p-limit@npm:3.1.0"
@@ -3117,13 +2872,6 @@ __metadata:
languageName: node
linkType: hard
-"path-key@npm:^2.0.0":
- version: 2.0.1
- resolution: "path-key@npm:2.0.1"
- checksum: f7ab0ad42fe3fb8c7f11d0c4f849871e28fbd8e1add65c370e422512fc5887097b9cf34d09c1747d45c942a8c1e26468d6356e2df3f740bf177ab8ca7301ebfd
- languageName: node
- linkType: hard
-
"path-key@npm:^3.1.0":
version: 3.1.1
resolution: "path-key@npm:3.1.1"
@@ -3159,13 +2907,6 @@ __metadata:
languageName: node
linkType: hard
-"pend@npm:~1.2.0":
- version: 1.2.0
- resolution: "pend@npm:1.2.0"
- checksum: 6c72f5243303d9c60bd98e6446ba7d30ae29e3d56fdb6fae8767e8ba6386f33ee284c97efe3230a0d0217e2b1723b8ab490b1bbf34fcbb2180dbc8a9de47850d
- languageName: node
- linkType: hard
-
"pg-connection-string@npm:^2.5.0":
version: 2.5.0
resolution: "pg-connection-string@npm:2.5.0"
@@ -3261,36 +3002,6 @@ __metadata:
languageName: node
linkType: hard
-"pify@npm:^2.3.0":
- version: 2.3.0
- resolution: "pify@npm:2.3.0"
- checksum: 9503aaeaf4577acc58642ad1d25c45c6d90288596238fb68f82811c08104c800e5a7870398e9f015d82b44ecbcbef3dc3d4251a1cbb582f6e5959fe09884b2ba
- languageName: node
- linkType: hard
-
-"pify@npm:^3.0.0":
- version: 3.0.0
- resolution: "pify@npm:3.0.0"
- checksum: 6cdcbc3567d5c412450c53261a3f10991665d660961e06605decf4544a61a97a54fefe70a68d5c37080ff9d6f4cf51444c90198d1ba9f9309a6c0d6e9f5c4fde
- languageName: node
- linkType: hard
-
-"pinkie-promise@npm:^2.0.0":
- version: 2.0.1
- resolution: "pinkie-promise@npm:2.0.1"
- dependencies:
- pinkie: ^2.0.0
- checksum: b53a4a2e73bf56b6f421eef711e7bdcb693d6abb474d57c5c413b809f654ba5ee750c6a96dd7225052d4b96c4d053cdcb34b708a86fceed4663303abee52fcca
- languageName: node
- linkType: hard
-
-"pinkie@npm:^2.0.0":
- version: 2.0.4
- resolution: "pinkie@npm:2.0.4"
- checksum: b12b10afea1177595aab036fc220785488f67b4b0fc49e7a27979472592e971614fa1c728e63ad3e7eb748b4ec3c3dbd780819331dad6f7d635c77c10537b9db
- languageName: node
- linkType: hard
-
"postcss@npm:^8.4.16":
version: 8.4.16
resolution: "postcss@npm:8.4.16"
@@ -3355,13 +3066,6 @@ __metadata:
languageName: node
linkType: hard
-"process-nextick-args@npm:~2.0.0":
- version: 2.0.1
- resolution: "process-nextick-args@npm:2.0.1"
- checksum: 1d38588e520dab7cea67cbbe2efdd86a10cc7a074c09657635e34f035277b59fbb57d09d8638346bf7090f8e8ebc070c96fa5fd183b777fff4f5edff5e9466cf
- languageName: node
- linkType: hard
-
"promise-inflight@npm:^1.0.1":
version: 1.0.1
resolution: "promise-inflight@npm:1.0.1"
@@ -3379,13 +3083,6 @@ __metadata:
languageName: node
linkType: hard
-"pseudomap@npm:^1.0.2":
- version: 1.0.2
- resolution: "pseudomap@npm:1.0.2"
- checksum: 856c0aae0ff2ad60881168334448e898ad7a0e45fe7386d114b150084254c01e200c957cf378378025df4e052c7890c5bd933939b0e0d2ecfcc1dc2f0b2991f5
- languageName: node
- linkType: hard
-
"punycode@npm:^2.1.0":
version: 2.1.1
resolution: "punycode@npm:2.1.1"
@@ -3409,21 +3106,6 @@ __metadata:
languageName: node
linkType: hard
-"readable-stream@npm:^2.3.0, readable-stream@npm:^2.3.5":
- version: 2.3.7
- resolution: "readable-stream@npm:2.3.7"
- dependencies:
- core-util-is: ~1.0.0
- inherits: ~2.0.3
- isarray: ~1.0.0
- process-nextick-args: ~2.0.0
- safe-buffer: ~5.1.1
- string_decoder: ~1.1.1
- util-deprecate: ~1.0.1
- checksum: e4920cf7549a60f8aaf694d483a0e61b2a878b969d224f89b3bc788b8d920075132c4b55a7494ee944c7b6a9a0eada28a7f6220d80b0312ece70bbf08eeca755
- languageName: node
- linkType: hard
-
"readable-stream@npm:^3.6.0":
version: 3.6.0
resolution: "readable-stream@npm:3.6.0"
@@ -3491,10 +3173,10 @@ __metadata:
languageName: node
linkType: hard
-"retry-as-promised@npm:^5.0.0":
- version: 5.0.0
- resolution: "retry-as-promised@npm:5.0.0"
- checksum: 4d17e0597f967db0516714f0f2b085e2d1e8ea592450b013a1e0cd41dad74a9c3d1eb3c45351887de4bca1c3ac5f74dd07ef9942a3fb0e4db996a83bb28cb46e
+"retry-as-promised@npm:^6.1.0":
+ version: 6.1.0
+ resolution: "retry-as-promised@npm:6.1.0"
+ checksum: cde3ad5c827d3f51b9161b9453dfd5eb8b8b6c22b6b405f7294eaa1939ef1966f8bd4c8a228ce2d66a24959d1dcc48b113c4c810ecdaddec2968b6d20576329d
languageName: node
linkType: hard
@@ -3523,9 +3205,9 @@ __metadata:
languageName: node
linkType: hard
-"rollup@npm:>=2.75.6 <2.77.0 || ~2.77.0":
- version: 2.77.3
- resolution: "rollup@npm:2.77.3"
+"rollup@npm:~2.78.0":
+ version: 2.78.1
+ resolution: "rollup@npm:2.78.1"
dependencies:
fsevents: ~2.3.2
dependenciesMeta:
@@ -3533,7 +3215,7 @@ __metadata:
optional: true
bin:
rollup: dist/bin/rollup
- checksum: b179c68249584565ddb5664a241e8e48c293b2207718d885b08ee25797d98857a383f06b544bb89819407da5a71557f4713309a278f61c4778bb32b1d3321a1c
+ checksum: 9034814383ca5bdb4bea6d499270aeb31cdb0bb884f81b0c6a1d19c63cc973f040e6ee09b7af8a7169dd231c090f4b44ef8b99c4bfdf884aceeb3dcefb8cfa14
languageName: node
linkType: hard
@@ -3546,20 +3228,13 @@ __metadata:
languageName: node
linkType: hard
-"safe-buffer@npm:^5.0.1, safe-buffer@npm:^5.1.1, safe-buffer@npm:~5.2.0":
+"safe-buffer@npm:^5.0.1, safe-buffer@npm:~5.2.0":
version: 5.2.1
resolution: "safe-buffer@npm:5.2.1"
checksum: b99c4b41fdd67a6aaf280fcd05e9ffb0813654894223afb78a31f14a19ad220bba8aba1cb14eddce1fcfb037155fe6de4e861784eb434f7d11ed58d1e70dd491
languageName: node
linkType: hard
-"safe-buffer@npm:~5.1.0, safe-buffer@npm:~5.1.1":
- version: 5.1.2
- resolution: "safe-buffer@npm:5.1.2"
- checksum: f2f1f7943ca44a594893a852894055cf619c1fbcb611237fc39e461ae751187e7baf4dc391a72125e0ac4fb2d8c5c0b3c71529622e6a58f46b960211e704903c
- languageName: node
- linkType: hard
-
"safer-buffer@npm:>= 2.1.2 < 3.0.0":
version: 2.1.2
resolution: "safer-buffer@npm:2.1.2"
@@ -3574,18 +3249,6 @@ __metadata:
languageName: node
linkType: hard
-"seek-bzip@npm:^1.0.5":
- version: 1.0.6
- resolution: "seek-bzip@npm:1.0.6"
- dependencies:
- commander: ^2.8.1
- bin:
- seek-bunzip: bin/seek-bunzip
- seek-table: bin/seek-bzip-table
- checksum: c2ab3291e7085558499efd4e99d1466ee6782f6c4a4e4c417aa859e1cd2f5117fb3b5444f3d27c38ec5908c0f0312e2a0bc69dff087751f97b3921b5bde4f9ed
- languageName: node
- linkType: hard
-
"semver@npm:^7.3.5, semver@npm:^7.3.7":
version: 7.3.7
resolution: "semver@npm:7.3.7"
@@ -3604,9 +3267,9 @@ __metadata:
languageName: node
linkType: hard
-"sequelize@npm:6.21.4":
- version: 6.21.4
- resolution: "sequelize@npm:6.21.4"
+"sequelize@npm:6.23.1":
+ version: 6.23.1
+ resolution: "sequelize@npm:6.23.1"
dependencies:
"@types/debug": ^4.1.7
"@types/validator": ^13.7.1
@@ -3617,7 +3280,7 @@ __metadata:
moment: ^2.29.1
moment-timezone: ^0.5.34
pg-connection-string: ^2.5.0
- retry-as-promised: ^5.0.0
+ retry-as-promised: ^6.1.0
semver: ^7.3.5
sequelize-pool: ^7.1.0
toposort-class: ^1.0.1
@@ -3631,6 +3294,8 @@ __metadata:
optional: true
mysql2:
optional: true
+ oracledb:
+ optional: true
pg:
optional: true
pg-hstore:
@@ -3641,7 +3306,7 @@ __metadata:
optional: true
tedious:
optional: true
- checksum: 6d066083125aa8a90286c82379964b5e54620daa7eac7f0d8b25c52cad93f8cae70cc4606a58097e815f57bad405969353d35321c1c9edfff27d953cec9ff064
+ checksum: cb34d8b6cd4c3aba19bb1d6c6af4904d6526053fab611e1ae39cc5ba8f949b5e0c581806bf02aef07bd4a87782ec7096d6f0df77bcb3c46cc1361ac04818141e
languageName: node
linkType: hard
@@ -3652,15 +3317,6 @@ __metadata:
languageName: node
linkType: hard
-"shebang-command@npm:^1.2.0":
- version: 1.2.0
- resolution: "shebang-command@npm:1.2.0"
- dependencies:
- shebang-regex: ^1.0.0
- checksum: 9eed1750301e622961ba5d588af2212505e96770ec376a37ab678f965795e995ade7ed44910f5d3d3cb5e10165a1847f52d3348c64e146b8be922f7707958908
- languageName: node
- linkType: hard
-
"shebang-command@npm:^2.0.0":
version: 2.0.0
resolution: "shebang-command@npm:2.0.0"
@@ -3670,13 +3326,6 @@ __metadata:
languageName: node
linkType: hard
-"shebang-regex@npm:^1.0.0":
- version: 1.0.0
- resolution: "shebang-regex@npm:1.0.0"
- checksum: 404c5a752cd40f94591dfd9346da40a735a05139dac890ffc229afba610854d8799aaa52f87f7e0c94c5007f2c6af55bdcaeb584b56691926c5eaf41dc8f1372
- languageName: node
- linkType: hard
-
"shebang-regex@npm:^3.0.0":
version: 3.0.0
resolution: "shebang-regex@npm:3.0.0"
@@ -3695,7 +3344,7 @@ __metadata:
languageName: node
linkType: hard
-"signal-exit@npm:^3.0.0, signal-exit@npm:^3.0.7":
+"signal-exit@npm:^3.0.7":
version: 3.0.7
resolution: "signal-exit@npm:3.0.7"
checksum: a2f098f247adc367dffc27845853e9959b9e88b01cb301658cfe4194352d8d2bb32e18467c786a7fe15f1d44b233ea35633d076d5e737870b7139949d1ab6318
@@ -3780,15 +3429,6 @@ __metadata:
languageName: node
linkType: hard
-"string_decoder@npm:~1.1.1":
- version: 1.1.1
- resolution: "string_decoder@npm:1.1.1"
- dependencies:
- safe-buffer: ~5.1.0
- checksum: 9ab7e56f9d60a28f2be697419917c50cac19f3e8e6c28ef26ed5f4852289fe0de5d6997d29becf59028556f2c62983790c1d9ba1e2a3cc401768ca12d5183a5b
- languageName: node
- linkType: hard
-
"strip-ansi@npm:^6.0.1":
version: 6.0.1
resolution: "strip-ansi@npm:6.0.1"
@@ -3798,22 +3438,6 @@ __metadata:
languageName: node
linkType: hard
-"strip-dirs@npm:^2.0.0":
- version: 2.1.0
- resolution: "strip-dirs@npm:2.1.0"
- dependencies:
- is-natural-number: ^4.0.1
- checksum: 9465547d71d8819daa7a5c9d4d783289ed8eac72eb06bd687bed382ce62af8ab8e6ffbda229805f5d2e71acce2ca4915e781c94190d284994cbc0b7cdc8303cc
- languageName: node
- linkType: hard
-
-"strip-eof@npm:^1.0.0":
- version: 1.0.0
- resolution: "strip-eof@npm:1.0.0"
- checksum: 40bc8ddd7e072f8ba0c2d6d05267b4e0a4800898c3435b5fb5f5a21e6e47dfaff18467e7aa0d1844bb5d6274c3097246595841fbfeb317e541974ee992cac506
- languageName: node
- linkType: hard
-
"strip-json-comments@npm:^3.1.0, strip-json-comments@npm:^3.1.1":
version: 3.1.1
resolution: "strip-json-comments@npm:3.1.1"
@@ -3821,7 +3445,16 @@ __metadata:
languageName: node
linkType: hard
-"strtok3@npm:^7.0.0-alpha.9":
+"strip-literal@npm:^0.4.1":
+ version: 0.4.2
+ resolution: "strip-literal@npm:0.4.2"
+ dependencies:
+ acorn: ^8.8.0
+ checksum: 831cdcaba61bc82c14ef5ca423a64bb8044b3b128abd15dff454d3fd05b0dbc7b4403760a7a636923d3c2e71a8e65174cef28ee9aef61f9a66819f865da4fdda
+ languageName: node
+ linkType: hard
+
+"strtok3@npm:^7.0.0":
version: 7.0.0
resolution: "strtok3@npm:7.0.0"
dependencies:
@@ -3851,76 +3484,59 @@ __metadata:
version: 0.0.0-use.local
resolution: "tanzanite@workspace:."
dependencies:
- "@discordjs/builders": ^1.1.0
- "@discordjs/rest": ^1.0.1
+ "@discordjs/builders": ^1.2.0
+ "@discordjs/rest": ^1.2.0
"@ironm00n/nbt-ts": ^1.4.0
- "@napi-rs/canvas": ^0.1.29
- "@notenoughupdates/discord.js-minesweeper": ^1.0.10
- "@notenoughupdates/events-intercept": ^3.0.1
+ "@napi-rs/canvas": ^0.1.30
+ "@notenoughupdates/discord-akairo": ^10.0.0-dev.1664158089.48d6368
"@notenoughupdates/humanize-duration": ^4.0.1
- "@notenoughupdates/simplify-number": ^1.0.1
- "@notenoughupdates/wolfram-alpha-api": ^1.0.2
"@sapphire/snowflake": ^3.2.2
- "@sentry/integrations": ^7.11.1
- "@sentry/node": ^7.11.1
- "@sentry/tracing": ^7.11.1
- "@sentry/types": ^7.11.1
+ "@sentry/integrations": ^7.13.0
+ "@sentry/node": ^7.13.0
+ "@sentry/tracing": ^7.13.0
+ "@sentry/types": ^7.13.0
+ "@tanzanite/deep-lock": ^1.1.1
+ "@tanzanite/discord.js-minesweeper": ^1.2.0
+ "@tanzanite/events-intercept": ^3.1.0
+ "@tanzanite/simplify-number": ^2.0.1
+ "@tanzanite/wolfram-alpha": ^1.1.0
"@types/eslint": ^8.4.6
- "@types/express": ^4.17.13
- "@types/lodash": ^4.14.184
- "@types/node": ^18.7.13
+ "@types/express": ^4.17.14
+ "@types/lodash-es": ^4
+ "@types/node": ^18.7.21
+ "@types/node-fetch": ^2.6.2
"@types/numeral": ^2.0.2
"@types/pg": ^8.6.5
- "@types/prettier": ^2.7.0
- "@types/rimraf": ^3.0.2
+ "@types/prettier": ^2.7.1
"@types/tinycolor2": ^1.4.3
- "@types/validator": ^13.7.5
- "@typescript-eslint/eslint-plugin": ^5.35.1
- "@typescript-eslint/parser": ^5.35.1
+ "@types/validator": ^13.7.7
+ "@typescript-eslint/eslint-plugin": ^5.38.0
+ "@typescript-eslint/parser": ^5.38.0
chalk: ^5.0.1
- deep-lock: ^1.0.0
- discord-akairo: "npm:@notenoughupdates/discord-akairo@dev"
- discord-api-types: 0.37.1
- discord.js: "npm:@notenoughupdates/discord.js@forum"
- eslint: ^8.23.0
+ discord-api-types: 0.37.10
+ discord.js: ^14.5.0
+ eslint: ^8.24.0
eslint-config-prettier: ^8.5.0
eslint-plugin-deprecation: ^1.3.2
fuse.js: ^6.6.2
- gif-to-apng: ^0.1.2
- googleapis: ^107.0.0
- lodash: ^4.17.21
- mathjs: ^11.1.0
+ googleapis: ^108.0.0
+ lodash-es: ^4.17.21
+ mathjs: ^11.2.1
nanoid: ^4.0.0
numeral: ^2.0.6
pg: ^8.8.0
pg-hstore: ^2.3.4
prettier: ^2.7.1
pretty-bytes: ^6.0.0
- rimraf: ^3.0.2
- sequelize: 6.21.4
+ sequelize: 6.23.1
tinycolor2: ^1.4.2
ts-essentials: ^9.3.0
- typescript: ^4.8.2
- vitest: ^0.22.1
- vm2: ^3.9.10
+ typescript: ^4.8.3
+ vitest: ^0.23.4
+ vm2: ^3.9.11
languageName: unknown
linkType: soft
-"tar-stream@npm:^1.5.2":
- version: 1.6.2
- resolution: "tar-stream@npm:1.6.2"
- dependencies:
- bl: ^1.0.0
- buffer-alloc: ^1.2.0
- end-of-stream: ^1.0.0
- fs-constants: ^1.0.0
- readable-stream: ^2.3.0
- to-buffer: ^1.1.1
- xtend: ^4.0.0
- checksum: a5d49e232d3e33321bbd150381b6a4e5046bf12b1c2618acb95435b7871efde4d98bd1891eb2200478a7142ef7e304e033eb29bbcbc90451a2cdfa1890e05245
- languageName: node
- linkType: hard
-
"tar@npm:^6.1.11, tar@npm:^6.1.2":
version: 6.1.11
resolution: "tar@npm:6.1.11"
@@ -3942,13 +3558,6 @@ __metadata:
languageName: node
linkType: hard
-"through@npm:^2.3.8":
- version: 2.3.8
- resolution: "through@npm:2.3.8"
- checksum: a38c3e059853c494af95d50c072b83f8b676a9ba2818dcc5b108ef252230735c54e0185437618596c790bbba8fcdaef5b290405981ffa09dce67b1f1bf190cbd
- languageName: node
- linkType: hard
-
"tiny-emitter@npm:^2.1.0":
version: 2.1.0
resolution: "tiny-emitter@npm:2.1.0"
@@ -3956,6 +3565,13 @@ __metadata:
languageName: node
linkType: hard
+"tinybench@npm:^2.1.5":
+ version: 2.1.5
+ resolution: "tinybench@npm:2.1.5"
+ checksum: 5a6d378271a00ace6fa6970404eb1efd539d3e9b9908a9cb6d66ad78acfd873762734f3fc69fe10d86217318871367997d2a8b9566039fd224c518493466aa96
+ languageName: node
+ linkType: hard
+
"tinycolor2@npm:^1.4.2":
version: 1.4.2
resolution: "tinycolor2@npm:1.4.2"
@@ -3963,10 +3579,10 @@ __metadata:
languageName: node
linkType: hard
-"tinypool@npm:^0.2.4":
- version: 0.2.4
- resolution: "tinypool@npm:0.2.4"
- checksum: f050bd36c89529a2a0d3f9c1fdbba3f317114e3ee6eb5d5ba72c51e887d45ef3ef8d8533fb2ca2eba7189d19d2231712b81b3a75e099248532f5563369929c33
+"tinypool@npm:^0.3.0":
+ version: 0.3.0
+ resolution: "tinypool@npm:0.3.0"
+ checksum: 92291c309ed8d004c1ee1ef7f610cd90352383f12c52b0ec16abd9ebc665c03626e7afbc9993df97f63e67fea002b5cc18ba5e8f90260643867cbcac278a183c
languageName: node
linkType: hard
@@ -3977,13 +3593,6 @@ __metadata:
languageName: node
linkType: hard
-"to-buffer@npm:^1.1.1":
- version: 1.1.1
- resolution: "to-buffer@npm:1.1.1"
- checksum: 6c897f58c2bdd8b8b1645ea515297732fec6dafb089bf36d12370c102ff5d64abf2be9410e0b1b7cfc707bada22d9a4084558010bfc78dd7023748dc5dd9a1ce
- languageName: node
- linkType: hard
-
"to-regex-range@npm:^5.0.1":
version: 5.0.1
resolution: "to-regex-range@npm:5.0.1"
@@ -3993,7 +3602,7 @@ __metadata:
languageName: node
linkType: hard
-"token-types@npm:^5.0.0-alpha.2":
+"token-types@npm:^5.0.1":
version: 5.0.1
resolution: "token-types@npm:5.0.1"
dependencies:
@@ -4081,44 +3690,34 @@ __metadata:
languageName: node
linkType: hard
-"typescript@npm:^4.8.2":
- version: 4.8.2
- resolution: "typescript@npm:4.8.2"
+"typescript@npm:^4.8.3":
+ version: 4.8.3
+ resolution: "typescript@npm:4.8.3"
bin:
tsc: bin/tsc
tsserver: bin/tsserver
- checksum: 7f5b81d0d558c9067f952c7af52ab7f19c2e70a916817929e4a5b256c93990bf3178eccb1ac8a850bc75df35f6781b6f4cb3370ce20d8b1ded92ed462348f628
+ checksum: 8286a5edcaf3d68e65c451aa1e7150ad1cf53ee0813c07ec35b7abdfdb10f355ecaa13c6a226a694ae7a67785fd7eeebf89f845da0b4f7e4a35561ddc459aba0
languageName: node
linkType: hard
-"typescript@patch:typescript@^4.8.2#~builtin<compat/typescript>":
- version: 4.8.2
- resolution: "typescript@patch:typescript@npm%3A4.8.2#~builtin<compat/typescript>::version=4.8.2&hash=a1c5e5"
+"typescript@patch:typescript@^4.8.3#~builtin<compat/typescript>":
+ version: 4.8.3
+ resolution: "typescript@patch:typescript@npm%3A4.8.3#~builtin<compat/typescript>::version=4.8.3&hash=a1c5e5"
bin:
tsc: bin/tsc
tsserver: bin/tsserver
- checksum: 5cb0f02f414f5405f4b0e7ee1fd7fa9177b6a8783c9017b6cad85f56ce4c4f93e0e6f2ce37e863cb597d44227cd009474c9fbd85bf7a50004e5557426cb58079
- languageName: node
- linkType: hard
-
-"unbzip2-stream@npm:^1.0.9":
- version: 1.4.3
- resolution: "unbzip2-stream@npm:1.4.3"
- dependencies:
- buffer: ^5.2.1
- through: ^2.3.8
- checksum: 0e67c4a91f4fa0fc7b4045f8b914d3498c2fc2e8c39c359977708ec85ac6d6029840e97f508675fdbdf21fcb8d276ca502043406f3682b70f075e69aae626d1d
+ checksum: 2222d2382fb3146089b1d27ce2b55e9d1f99cc64118f1aba75809b693b856c5d3c324f052f60c75b577947fc538bc1c27bad0eb76cbdba9a63a253489504ba7e
languageName: node
linkType: hard
"underscore@npm:^1.13.1":
- version: 1.13.4
- resolution: "underscore@npm:1.13.4"
- checksum: 6b04f66cd454e8793a552dc49c71e24e5208a29b9d9c0af988a96948af79103399c36fb15db43f3629bfed152f8b1fe94f44e1249e9d196069c0fc7edfadb636
+ version: 1.13.6
+ resolution: "underscore@npm:1.13.6"
+ checksum: d5cedd14a9d0d91dd38c1ce6169e4455bb931f0aaf354108e47bd46d3f2da7464d49b2171a5cf786d61963204a42d01ea1332a903b7342ad428deaafaf70ec36
languageName: node
linkType: hard
-"undici@npm:^5.8.0, undici@npm:^5.9.1":
+"undici@npm:^5.10.0":
version: 5.10.0
resolution: "undici@npm:5.10.0"
checksum: 7ba2b71dccc74cd2bdf645b83e9aaef374ae04855943d0a2f42a3d0b9e5556f37cc9b5156fb5288277a2fa95fd46a56f3ae0d5cf73db3f008d75ec41104b136c
@@ -4159,14 +3758,14 @@ __metadata:
languageName: node
linkType: hard
-"util-deprecate@npm:^1.0.1, util-deprecate@npm:~1.0.1":
+"util-deprecate@npm:^1.0.1":
version: 1.0.2
resolution: "util-deprecate@npm:1.0.2"
checksum: 474acf1146cb2701fe3b074892217553dfcf9a031280919ba1b8d651a068c9b15d863b7303cb15bd00a862b498e6cf4ad7b4a08fb134edd5a6f7641681cb54a2
languageName: node
linkType: hard
-"uuid@npm:^8.0.0, uuid@npm:^8.3.2":
+"uuid@npm:^8.3.2":
version: 8.3.2
resolution: "uuid@npm:8.3.2"
bin:
@@ -4175,6 +3774,15 @@ __metadata:
languageName: node
linkType: hard
+"uuid@npm:^9.0.0":
+ version: 9.0.0
+ resolution: "uuid@npm:9.0.0"
+ bin:
+ uuid: dist/bin/uuid
+ checksum: 8dd2c83c43ddc7e1c71e36b60aea40030a6505139af6bee0f382ebcd1a56f6cd3028f7f06ffb07f8cf6ced320b76aea275284b224b002b289f89fe89c389b028
+ languageName: node
+ linkType: hard
+
"validator@npm:^13.7.0":
version: 13.7.0
resolution: "validator@npm:13.7.0"
@@ -4183,14 +3791,14 @@ __metadata:
linkType: hard
"vite@npm:^2.9.12 || ^3.0.0-0":
- version: 3.0.9
- resolution: "vite@npm:3.0.9"
+ version: 3.1.3
+ resolution: "vite@npm:3.1.3"
dependencies:
- esbuild: ^0.14.47
+ esbuild: ^0.15.6
fsevents: ~2.3.2
postcss: ^8.4.16
resolve: ^1.22.1
- rollup: ">=2.75.6 <2.77.0 || ~2.77.0"
+ rollup: ~2.78.0
peerDependencies:
less: "*"
sass: "*"
@@ -4210,13 +3818,13 @@ __metadata:
optional: true
bin:
vite: bin/vite.js
- checksum: 6341aa43579ae45f8a383bdc0c5041dea3dff98f14e0a546d6d884a864134b00082246a28d1de8adff0ce0dd92b468c7ade8f972ffe1ed97258671d63e0f16f7
+ checksum: af13c9820c292792f02d0a25fd46d8557e627b93f95bc05b5f7f1261e9565e9e69fda2df0c0898f248edb811ebcac5400a85a81625ef29749f50b18273439d91
languageName: node
linkType: hard
-"vitest@npm:^0.22.1":
- version: 0.22.1
- resolution: "vitest@npm:0.22.1"
+"vitest@npm:^0.23.4":
+ version: 0.23.4
+ resolution: "vitest@npm:0.23.4"
dependencies:
"@types/chai": ^4.3.3
"@types/chai-subset": ^1.3.3
@@ -4224,7 +3832,9 @@ __metadata:
chai: ^4.3.6
debug: ^4.3.4
local-pkg: ^0.4.2
- tinypool: ^0.2.4
+ strip-literal: ^0.4.1
+ tinybench: ^2.1.5
+ tinypool: ^0.3.0
tinyspy: ^1.0.2
vite: ^2.9.12 || ^3.0.0-0
peerDependencies:
@@ -4246,19 +3856,19 @@ __metadata:
optional: true
bin:
vitest: vitest.mjs
- checksum: 7abe50ceb51181e77cd62eb3a07c2da17f13078f09be34cc2e98f1f94a77eba33a56c644d48ae16bb474945ffc1cfc8664b1f4976c3de495c5e474057420c4ca
+ checksum: c0356ff585d6f85678abe4e4f61362ea55af87b15f9b1fc478f5fed511627efa5f849a1530709fa2ca09a3f5e93dd16dfaf6570c9cd84ca6fd6ef387aa8ee512
languageName: node
linkType: hard
-"vm2@npm:^3.9.10":
- version: 3.9.10
- resolution: "vm2@npm:3.9.10"
+"vm2@npm:^3.9.11":
+ version: 3.9.11
+ resolution: "vm2@npm:3.9.11"
dependencies:
acorn: ^8.7.0
acorn-walk: ^8.2.0
bin:
vm2: bin/vm2
- checksum: 5534df3d3f3aa9060ab23fd22a2f5e756c19bec7b9af50028aa05c6f7c21c3da303101f1982004964d5320f9484d02a2d299e841994dce03af7fe1061871b518
+ checksum: aab39e6e4b59146d24abacd79f490e854a6e058a8b23d93d2be5aca7720778e2605d2cc028ccc4a5f50d3d91b0c38be9a6247a80d2da1a6de09425cc437770b4
languageName: node
linkType: hard
@@ -4279,17 +3889,6 @@ __metadata:
languageName: node
linkType: hard
-"which@npm:^1.2.9":
- version: 1.3.1
- resolution: "which@npm:1.3.1"
- dependencies:
- isexe: ^2.0.0
- bin:
- which: ./bin/which
- checksum: f2e185c6242244b8426c9df1510e86629192d93c1a986a7d2a591f2c24869e7ffd03d6dac07ca863b2e4c06f59a4cc9916c585b72ee9fa1aa609d0124df15e04
- languageName: node
- linkType: hard
-
"which@npm:^2.0.1, which@npm:^2.0.2":
version: 2.0.2
resolution: "which@npm:2.0.2"
@@ -4333,9 +3932,9 @@ __metadata:
languageName: node
linkType: hard
-"ws@npm:^8.8.1":
- version: 8.8.1
- resolution: "ws@npm:8.8.1"
+"ws@npm:^8.9.0":
+ version: 8.9.0
+ resolution: "ws@npm:8.9.0"
peerDependencies:
bufferutil: ^4.0.1
utf-8-validate: ^5.0.2
@@ -4344,7 +3943,7 @@ __metadata:
optional: true
utf-8-validate:
optional: true
- checksum: 2152cf862cae0693f3775bc688a6afb2e989d19d626d215e70f5fcd8eb55b1c3b0d3a6a4052905ec320e2d7734e20aeedbf9744496d62f15a26ad79cf4cf7dae
+ checksum: 23aa0f021b2eb65c108ec4c3e08c0d81ba01f82b500432dfe327fd6be36079c1d81fdb0eac6464d2a0eb49904d34a9ab8c59619d673fa07b8346f83aeb0cbf12
languageName: node
linkType: hard
@@ -4355,13 +3954,6 @@ __metadata:
languageName: node
linkType: hard
-"yallist@npm:^2.1.2":
- version: 2.1.2
- resolution: "yallist@npm:2.1.2"
- checksum: 9ba99409209f485b6fcb970330908a6d41fa1c933f75e08250316cce19383179a6b70a7e0721b89672ebb6199cc377bf3e432f55100da6a7d6e11902b0a642cb
- languageName: node
- linkType: hard
-
"yallist@npm:^4.0.0":
version: 4.0.0
resolution: "yallist@npm:4.0.0"
@@ -4369,16 +3961,6 @@ __metadata:
languageName: node
linkType: hard
-"yauzl@npm:^2.4.2":
- version: 2.10.0
- resolution: "yauzl@npm:2.10.0"
- dependencies:
- buffer-crc32: ~0.2.3
- fd-slicer: ~1.1.0
- checksum: 7f21fe0bbad6e2cb130044a5d1d0d5a0e5bf3d8d4f8c4e6ee12163ce798fee3de7388d22a7a0907f563ac5f9d40f8699a223d3d5c1718da90b0156da6904022b
- languageName: node
- linkType: hard
-
"yocto-queue@npm:^0.1.0":
version: 0.1.0
resolution: "yocto-queue@npm:0.1.0"
@@ -4386,9 +3968,9 @@ __metadata:
languageName: node
linkType: hard
-"zod@npm:^3.17.10":
- version: 3.18.0
- resolution: "zod@npm:3.18.0"
- checksum: 86a9a9928f4b40a07020d4b9832842fa4a70050c2d7bd1b2866bc1acfd734aa53a40f87a99a4312a637341a608b0105770c7a1f83b56df78e97691b4f5badcd8
+"zod@npm:^3.19.1":
+ version: 3.19.1
+ resolution: "zod@npm:3.19.1"
+ checksum: 56e420ea5845912324a8fc61833714a2aec84954e418b52660d76502183c6e62fef9447cbfa64349640c5ce190cf2c24267e006bb80f066183e2f3fa9fe11864
languageName: node
linkType: hard